]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Implement indices that occur in sort order and the LIMIT...OFFSET clause
authordrh <drh@noemail.net>
Tue, 6 Nov 2001 04:00:18 +0000 (04:00 +0000)
committerdrh <drh@noemail.net>
Tue, 6 Nov 2001 04:00:18 +0000 (04:00 +0000)
of SELECT statements. (CVS 301)

FossilOrigin-Name: eb07768ae93f14bf6c150c1c4329948857a9d01c

manifest
manifest.uuid
src/parse.y
src/select.c
src/sqliteInt.h
src/tokenize.c
src/util.c
src/vdbe.c
src/vdbe.h

index 3b815255a890cdec5f356da0f620ba1ec9eedea0..4a6c2336a4496306ec568aa5a73582e1fa7387bd 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Increase\smaximum\srow\ssize\sto\s1MB.\s(CVS\s300)
-D 2001-11-04T18:32:47
+C Implement\sindices\sthat\soccur\sin\ssort\sorder\sand\sthe\sLIMIT...OFFSET\sclause\nof\sSELECT\sstatements.\s(CVS\s301)
+D 2001-11-06T04:00:18
 F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
 F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -33,24 +33,24 @@ F src/os.c 66b677479eae37e30bdfbe32deb0fe6a2efca983
 F src/os.h bed702c9e3b768bc3cb1b12c90b83d099c1546be
 F src/pager.c 0bd0b4b693edb43c72774e3e749d8667e2ae7094
 F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
-F src/parse.y 148e4cd134d3cbd816dcb0df50e49e498faa6ba4
+F src/parse.y 5295f393f41ea89958287e5738e6c12c7cd67482
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
-F src/select.c c34b02eafaa69fde6b4428df7861c3417b3079f9
+F src/select.c 008d79761a6025e4db490c8f732e32631c0c57c3
 F src/shell.c 71597951753b56a97fea1c7a30908f31e635c00c
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
-F src/sqliteInt.h fa9f56b77e0790f0ec329195c2255e2d8e440b0a
+F src/sqliteInt.h fc2f7da1fee1e871b20b375c50c582065d891c7f
 F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
 F src/tclsqlite.c 4896e078495bf868742f5394dcf01c5efe5bea02
 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
 F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
-F src/tokenize.c 9ede24b17630351d70258bf8fa4f70f5990d45ae
+F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
 F src/update.c 4eeb154a2da8a934d180e2d9e4211ac0a7a4ce8b
-F src/util.c aa4d2de60cb2445239b71c79c3a8c0b7c0d3336a
-F src/vdbe.c a71e73e9a4a63fe2f63546a1a43fce4de5136476
-F src/vdbe.h c29e6fdfa157b3cce18258c05d9d533eb9cd1377
+F src/util.c ac83973ecc647d3d3c58708f148442365abf9b94
+F src/vdbe.c 9f6ff3444a38d9bba27497be56e4ad386b316cbb
+F src/vdbe.h ea71a2c29d43c03283dee30237a01f4726900b29
 F src/where.c 601f096f2a37ca688a775ca36d33534b13b876cb
 F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
 F test/bigrow.test 9458134d67f81559845f934fdd6802fe19a68ad1
@@ -114,7 +114,7 @@ F www/speed.tcl 212a91d555384e01873160d6a189f1490c791bc2
 F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
-P 0fd2874205f1a4b89fc069cb429c1b0c7a0b99c1
-R 810197be2f3f50401607f0c17a5fe11e
+P 7dd58fad398253608f55867cf1c7749eef005657
+R 6b4d638b3f341e525807c77329fb1dc1
 U drh
-Z 863cf3e2c644c7eb0aa13f1cb68860b5
+Z e5f14755e0856f35fd2676a75ffdfa97
index 1cb9881ffa5cc89757052daa419058a50bc45582..475a506a2c9df0403902daedb5e500cdc97d8a23 100644 (file)
@@ -1 +1 @@
-7dd58fad398253608f55867cf1c7749eef005657
\ No newline at end of file
+eb07768ae93f14bf6c150c1c4329948857a9d01c
\ No newline at end of file
index 1180ff1782c6d93c0c6fadde7e1b6b0560977141..86679e828cb9e16478920168c7b74c25297e8f31 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.37 2001/10/13 02:59:09 drh Exp $
+** @(#) $Id: parse.y,v 1.38 2001/11/06 04:00:18 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
 %include {
 #include "sqliteInt.h"
 #include "parse.h"
+
+/*
+** A structure for holding two integers
+*/
+struct twoint { int a,b; };
 }
 
 // These are extra tokens used by the lexer but never seen by the
@@ -96,6 +101,7 @@ id(A) ::= PRAGMA(X).     {A = X;}
 id(A) ::= CLUSTER(X).    {A = X;}
 id(A) ::= ID(X).         {A = X;}
 id(A) ::= TEMP(X).       {A = X;}
+id(A) ::= OFFSET(X).     {A = X;}
 
 // And "ids" is an identifer-or-string.
 //
@@ -179,8 +185,8 @@ joinop(A) ::= UNION ALL.  {A = TK_ALL;}
 joinop(A) ::= INTERSECT.  {A = TK_INTERSECT;}
 joinop(A) ::= EXCEPT.     {A = TK_EXCEPT;}
 oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
-                 groupby_opt(P) having_opt(Q) orderby_opt(Z). {
-  A = sqliteSelectNew(W,X,Y,P,Q,Z,D);
+                 groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
+  A = sqliteSelectNew(W,X,Y,P,Q,Z,D,L.a,L.b);
 }
 
 // The "distinct" nonterminal is true (1) if the DISTINCT keyword is
@@ -259,6 +265,14 @@ groupby_opt(A) ::= GROUP BY exprlist(X).  {A = X;}
 having_opt(A) ::= .                {A = 0;}
 having_opt(A) ::= HAVING expr(X).  {A = X;}
 
+%type limit_opt {struct twoint}
+limit_opt(A) ::= .                  {A.a = -1; A.b = 0;}
+limit_opt(A) ::= LIMIT INTEGER(X).  {A.a = atoi(X.z); A.b = 0;}
+limit_opt(A) ::= LIMIT INTEGER(X) limit_sep INTEGER(Y). 
+                                    {A.a = atoi(X.z); A.b = atoi(Y.z);}
+limit_sep ::= OFFSET.
+limit_sep ::= COMMA.
+
 /////////////////////////// The DELETE statement /////////////////////////////
 //
 cmd ::= DELETE FROM ids(X) where_opt(Y).
index bf17fa920dd75c42ef7979352833836d7c3e17be..2e1a4c06992763b8bad8131fe28285c06f1a3287 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.45 2001/11/01 14:41:34 drh Exp $
+** $Id: select.c,v 1.46 2001/11/06 04:00:19 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -27,7 +27,9 @@ Select *sqliteSelectNew(
   ExprList *pGroupBy,   /* the GROUP BY clause */
   Expr *pHaving,        /* the HAVING clause */
   ExprList *pOrderBy,   /* the ORDER BY clause */
-  int isDistinct        /* true if the DISTINCT keyword is present */
+  int isDistinct,       /* true if the DISTINCT keyword is present */
+  int nLimit,           /* LIMIT value.  -1 means not used */
+  int nOffset           /* OFFSET value.  -1 means not used */
 ){
   Select *pNew;
   pNew = sqliteMalloc( sizeof(*pNew) );
@@ -47,6 +49,8 @@ Select *sqliteSelectNew(
     pNew->pOrderBy = pOrderBy;
     pNew->isDistinct = isDistinct;
     pNew->op = TK_SELECT;
+    pNew->nLimit = nLimit;
+    pNew->nOffset = nOffset;
   }
   return pNew;
 }
@@ -203,7 +207,7 @@ static int selectInnerLoop(
   /* If none of the above, send the data to the callback function.
   */
   {
-    sqliteVdbeAddOp(v, OP_Callback, nColumn, 0);
+    sqliteVdbeAddOp(v, OP_Callback, nColumn, iBreak);
   }
   return 0;
 }
@@ -219,7 +223,7 @@ static void generateSortTail(Vdbe *v, int nColumn){
   int addr;
   sqliteVdbeAddOp(v, OP_Sort, 0, 0);
   addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end);
-  sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0);
+  sqliteVdbeAddOp(v, OP_SortCallback, nColumn, end);
   sqliteVdbeAddOp(v, OP_Goto, 0, addr);
   sqliteVdbeResolveLabel(v, end);
   sqliteVdbeAddOp(v, OP_SortReset, 0, 0);
@@ -854,6 +858,16 @@ int sqliteSelect(
   v = sqliteGetVdbe(pParse);
   if( v==0 ) return 1;
 
+  /* Set the limiter
+  */
+  if( p->nLimit<=0 ){
+    p->nOffset = 0;
+  }else{
+    if( p->nOffset<0 ) p->nOffset = 0;
+    sqliteVdbeAddOp(v, OP_Limit, p->nLimit, p->nOffset);
+  }
+    
+
   /* Identify column names if we will be using in the callback.  This
   ** step is skipped if the output is going to a table or a memory cell.
   */
index c1232e6845218279dd05406984f3e25511ec6edf..1f170d91d7d796a15c9fe1156b3211ef9d5ce716 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.66 2001/11/04 18:32:47 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.67 2001/11/06 04:00:19 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -328,6 +328,7 @@ struct Select {
   ExprList *pOrderBy;    /* The ORDER BY clause */
   int op;                /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
   Select *pPrior;        /* Prior select in a compound select statement */
+  int nLimit, nOffset;   /* LIMIT and OFFSET values.  -1 means not used */
 };
 
 /*
@@ -407,6 +408,7 @@ int sqliteStrNICmp(const char *, const char *, int);
 int sqliteHashNoCase(const char *, int);
 int sqliteCompare(const char *, const char *);
 int sqliteSortCompare(const char *, const char *);
+void sqliteRealToSortable(double r, char *);
 #ifdef MEMORY_DEBUG
   void *sqliteMalloc_(int,char*,int);
   void sqliteFree_(void*,char*,int);
@@ -449,7 +451,8 @@ void sqliteIdListDelete(IdList*);
 void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*);
 void sqliteDropIndex(Parse*, Token*);
 int sqliteSelect(Parse*, Select*, int, int);
-Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,int);
+Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,
+                        int,int,int);
 void sqliteSelectDelete(Select*);
 void sqliteDeleteFrom(Parse*, Token*, Expr*);
 void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
index 61edd6202eae7d802ed986b0eb75df36c54abed0..1917c652dcc436fb3ccdc0845d6b4a637007cf26 100644 (file)
@@ -15,7 +15,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.31 2001/11/04 18:32:48 drh Exp $
+** $Id: tokenize.c,v 1.32 2001/11/06 04:00:19 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -73,9 +73,11 @@ static Keyword aKeywordTable[] = {
   { "ISNULL",            0, TK_ISNULL,           0 },
   { "KEY",               0, TK_KEY,              0 },
   { "LIKE",              0, TK_LIKE,             0 },
+  { "LIMIT",             0, TK_LIMIT,            0 },
   { "NOT",               0, TK_NOT,              0 },
   { "NOTNULL",           0, TK_NOTNULL,          0 },
   { "NULL",              0, TK_NULL,             0 },
+  { "OFFSET",            0, TK_OFFSET,           0 },
   { "ON",                0, TK_ON,               0 },
   { "OR",                0, TK_OR,               0 },
   { "ORDER",             0, TK_ORDER,            0 },
index 3d0fa4c9b78034617bbb2efabef093874dd2621c..88b2f2448150a80eb413c1c0eba3146efd616a8e 100644 (file)
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.30 2001/10/22 02:58:10 drh Exp $
+** $Id: util.c,v 1.31 2001/11/06 04:00:19 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -754,6 +754,92 @@ int sqliteSortCompare(const char *a, const char *b){
   return res;
 }
 
+/*
+** Some powers of 64.  These numbers and their recipricals should
+** all have exact representations in the floating point format.
+*/
+#define _64e3  (64.0 * 64.0 * 64.0)
+#define _64e4  (64.0 * 64.0 * 64.0 * 64.0)
+#define _64e15 (_64e3 * _64e4 * _64e4 * _64e4)
+#define _64e16 (_64e4 * _64e4 * _64e4 * _64e4)
+#define _64e63 (_64e15 * _64e16 * _64e16 * _64e16)
+#define _64e64 (_64e16 * _64e16 * _64e16 * _64e16)
+
+/*
+** The following procedure converts a double-precision floating point
+** number into a string.  The resulting string has the property that
+** two such strings comparied using strcmp() or memcmp() will give the
+** same results as comparing the original floating point numbers.
+**
+** This routine is used to generate database keys from floating point
+** numbers such that the keys sort in the same order as the original
+** floating point numbers even though the keys are compared using
+** memcmp().
+**
+** The calling function should have allocated at least 14 characters
+** of space for the buffer z[].
+*/
+void sqliteRealToSortable(double r, char *z){
+  int neg;
+  int exp;
+  int cnt = 0;
+
+  /* This array maps integers between 0 and 63 into base-64 digits.
+  ** The digits must be chosen such at their ASCII codes are increasing.
+  ** This means we can not use the traditional base-64 digit set. */
+  static const char zDigit[] = 
+     "0123456789"
+     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+     "abcdefghijklmnopqrstuvwxyz"
+     "|~";
+  if( r<0.0 ){
+    neg = 1;
+    r = -r;
+    *z++ = '-';
+  } else {
+    neg = 0;
+    *z++ = '0';
+  }
+  exp = 0;
+
+  if( r==0.0 ){
+    exp = -1024;
+  }else if( r<(0.5/64.0) ){
+    while( r < 0.5/_64e64 && exp > -961  ){ r *= _64e64;  exp -= 64; }
+    while( r < 0.5/_64e16 && exp > -1009 ){ r *= _64e16;  exp -= 16; }
+    while( r < 0.5/_64e4  && exp > -1021 ){ r *= _64e4;   exp -= 4; }
+    while( r < 0.5/64.0   && exp > -1024 ){ r *= 64.0;    exp -= 1; }
+  }else if( r>=0.5 ){
+    while( r >= 0.5*_64e63 && exp < 960  ){ r *= 1.0/_64e64; exp += 64; }
+    while( r >= 0.5*_64e15 && exp < 1008 ){ r *= 1.0/_64e16; exp += 16; }
+    while( r >= 0.5*_64e3  && exp < 1020 ){ r *= 1.0/_64e4;  exp += 4; }
+    while( r >= 0.5        && exp < 1023 ){ r *= 1.0/64.0;   exp += 1; }
+  }
+  if( neg ){
+    exp = -exp;
+    r = -r;
+  }
+  exp += 1024;
+  r += 0.5;
+  if( exp<0 ) return;
+  if( exp>=2048 || r>=1.0 ){
+    strcpy(z, "~~~~~~~~~~~~");
+    return;
+  }
+  *z++ = zDigit[(exp>>6)&0x3f];
+  *z++ = zDigit[exp & 0x3f];
+  while( r>0.0 && cnt<10 ){
+    int digit;
+    r *= 64.0;
+    digit = r;
+    assert( digit>=0 && digit<64 );
+    *z++ = zDigit[digit & 0x3f];
+    r -= digit;
+    cnt++;
+  }
+  *z = 0;
+}
+
 #ifdef SQLITE_UTF8
 /*
 ** X is a pointer to the first byte of a UTF-8 character.  Increment
index b121e186e4ce9983fb3a46928110899a6511ac5f..5aea72e670f7ca34f37b92076bd11c65ef68c84a 100644 (file)
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.92 2001/11/04 18:32:48 drh Exp $
+** $Id: vdbe.c,v 1.93 2001/11/06 04:00:19 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -87,6 +87,13 @@ struct Sorter {
 */
 #define NSORT 30
 
+/*
+** Number of bytes of string storage space available to each stack
+** layer without having to malloc.  NBFS is short for Number of Bytes
+** For Strings.
+*/
+#define NBFS 30
+
 /*
 ** A single level of the stack is an instance of the following
 ** structure.  Except, string values are stored on a separate
@@ -99,6 +106,7 @@ struct Stack {
   int n;         /* Number of characters in string value, including '\0' */
   int flags;     /* Some combination of STK_Null, STK_Str, STK_Dyn, etc. */
   double r;      /* Real value */
+  char z[NBFS];  /* Space for short strings */
 };
 typedef struct Stack Stack;
 
@@ -120,6 +128,7 @@ typedef struct Mem Mem;
 #define STK_Int       0x0004   /* Value is an integer */
 #define STK_Real      0x0008   /* Value is a real number */
 #define STK_Dyn       0x0010   /* Need to call sqliteFree() on zStack[*] */
+#define STK_Static    0x0020   /* zStack[] points to a static string */
 
 /*
 ** An Agg structure describes an Aggregator.  Each Agg consists of
@@ -201,6 +210,8 @@ struct Vdbe {
   Set *aSet;          /* An array of sets */
   int nFetch;         /* Number of OP_Fetch instructions executed */
   int nCallback;      /* Number of callbacks invoked so far */
+  int iLimit;         /* Limit on the number of callbacks remaining */
+  int iOffset;        /* Offset before beginning to do callbacks */
 };
 
 /*
@@ -534,22 +545,17 @@ static AggElem *_AggInFocus(Agg *p){
 static int hardStringify(Vdbe *p, int i){
   Stack *pStack = &p->aStack[i];
   char **pzStack = &p->zStack[i];
-  char zBuf[30];
   int fg = pStack->flags;
   if( fg & STK_Real ){
-    sprintf(zBuf,"%.15g",pStack->r);
+    sprintf(pStack->z,"%.15g",pStack->r);
   }else if( fg & STK_Int ){
-    sprintf(zBuf,"%d",pStack->i);
+    sprintf(pStack->z,"%d",pStack->i);
   }else{
-    p->zStack[i] = "";
-    pStack->n = 1;
-    pStack->flags |= STK_Str;
-    return 0;
+    pStack->z[0] = 0;
   }
-  *pzStack = sqliteStrDup(zBuf);
-  if( *pzStack==0 ) return 1;
+  *pzStack = pStack->z;
   pStack->n = strlen(*pzStack)+1;
-  pStack->flags |= STK_Str|STK_Dyn;
+  pStack->flags = STK_Str;
   return 0;
 }
 
@@ -560,7 +566,7 @@ static int hardStringify(Vdbe *p, int i){
 static void hardRelease(Vdbe *p, int i){
   sqliteFree(p->zStack[i]);
   p->zStack[i] = 0;
-  p->aStack[i].flags &= ~(STK_Str|STK_Dyn);
+  p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static);
 }
 
 /*
@@ -675,6 +681,27 @@ static int hardNeedStack(Vdbe *p, int N){
   return 0;
 }
 
+/*
+** Return TRUE if zNum is a floating-point or integer number.
+*/
+static int isNumber(const char *zNum){
+  if( *zNum=='-' || *zNum=='+' ) zNum++;
+  if( !isdigit(*zNum) ) return 0;
+  while( isdigit(*zNum) ) zNum++;
+  if( *zNum==0 ) return 1;
+  if( *zNum!='.' ) return 0;
+  zNum++;
+  if( !isdigit(*zNum) ) return 0;
+  while( isdigit(*zNum) ) zNum++;
+  if( *zNum==0 ) return 1;
+  if( *zNum!='e' && *zNum!='E' ) return 0;
+  zNum++;
+  if( *zNum=='-' || *zNum=='+' ) zNum++;
+  if( !isdigit(*zNum) ) return 0;
+  while( isdigit(*zNum) ) zNum++;
+  return *zNum==0;
+}
+
 /*
 ** Delete a keylist
 */
@@ -822,22 +849,22 @@ static char *zOpName[] = { 0,
   "MemStore",          "ListWrite",         "ListRewind",        "ListRead",
   "ListReset",         "SortPut",           "SortMakeRec",       "SortMakeKey",
   "Sort",              "SortNext",          "SortCallback",      "SortReset",
-  "FileOpen",          "FileRead",          "FileColumn",        "FileClose",
-  "AggReset",          "AggFocus",          "AggIncr",           "AggNext",
-  "AggSet",            "AggGet",            "SetInsert",         "SetFound",
-  "SetNotFound",       "SetClear",          "MakeRecord",        "MakeKey",
-  "MakeIdxKey",        "Goto",              "If",                "Halt",
-  "ColumnCount",       "ColumnName",        "Callback",          "NullCallback",
-  "Integer",           "String",            "Null",              "Pop",
-  "Dup",               "Pull",              "Add",               "AddImm",
-  "Subtract",          "Multiply",          "Divide",            "Remainder",
-  "BitAnd",            "BitOr",             "BitNot",            "ShiftLeft",
-  "ShiftRight",        "AbsValue",          "Precision",         "Min",
-  "Max",               "Like",              "Glob",              "Eq",
-  "Ne",                "Lt",                "Le",                "Gt",
-  "Ge",                "IsNull",            "NotNull",           "Negative",
-  "And",               "Or",                "Not",               "Concat",
-  "Noop",              "Strlen",            "Substr",          
+  "FileOpen",          "FileRead",          "FileColumn",        "AggReset",
+  "AggFocus",          "AggIncr",           "AggNext",           "AggSet",
+  "AggGet",            "SetInsert",         "SetFound",          "SetNotFound",
+  "MakeRecord",        "MakeKey",           "MakeIdxKey",        "Goto",
+  "If",                "Halt",              "ColumnCount",       "ColumnName",
+  "Callback",          "NullCallback",      "Integer",           "String",
+  "Pop",               "Dup",               "Pull",              "Add",
+  "AddImm",            "Subtract",          "Multiply",          "Divide",
+  "Remainder",         "BitAnd",            "BitOr",             "BitNot",
+  "ShiftLeft",         "ShiftRight",        "AbsValue",          "Precision",
+  "Min",               "Max",               "Like",              "Glob",
+  "Eq",                "Ne",                "Lt",                "Le",
+  "Gt",                "Ge",                "IsNull",            "NotNull",
+  "Negative",          "And",               "Or",                "Not",
+  "Concat",            "Noop",              "Strlen",            "Substr",
+  "Limit",
 };
 
 /*
@@ -1119,25 +1146,11 @@ case OP_String: {
   }else{
     zStack[i] = z;
     aStack[i].n = strlen(z) + 1;
-    aStack[i].flags = STK_Str;
+    aStack[i].flags = STK_Str | STK_Static;
   }
   break;
 }
 
-#if 0 /* NOT USED */
-/* Opcode: Null * * *
-**
-** Push a NULL value onto the stack.
-*/
-case OP_Null: {
-  int i = ++p->tos;
-  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
-  zStack[i] = 0;
-  aStack[i].flags = STK_Null;
-  break;
-}
-#endif
-
 /* Opcode: Pop P1 * *
 **
 ** P1 elements are popped off of the top of stack and discarded.
@@ -1162,13 +1175,21 @@ case OP_Dup: {
   int j = ++p->tos;
   VERIFY( if( i<0 ) goto not_enough_stack; )
   VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
-  aStack[j] = aStack[i];
-  if( aStack[i].flags & STK_Dyn ){
-    zStack[j] = sqliteMalloc( aStack[j].n );
-    if( zStack[j]==0 ) goto no_mem;
-    memcpy(zStack[j], zStack[i], aStack[j].n);
-  }else{
-    zStack[j] = zStack[i];
+  memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS);
+  if( aStack[j].flags & STK_Str ){
+    if( aStack[j].flags & STK_Static ){
+      zStack[j] = zStack[i];
+      aStack[j].flags = STK_Str | STK_Static;
+    }else if( aStack[i].n<=NBFS ){
+      memcpy(aStack[j].z, zStack[i], aStack[j].n);
+      zStack[j] = aStack[j].z;
+      aStack[j].flags = STK_Str;
+    }else{
+      zStack[j] = sqliteMalloc( aStack[j].n );
+      if( zStack[j]==0 ) goto no_mem;
+      memcpy(zStack[j], zStack[i], aStack[j].n);
+      aStack[j].flags = STK_Str | STK_Dyn;
+    }
   }
   break;
 }
@@ -1194,10 +1215,18 @@ case OP_Pull: {
   tz = zStack[from];
   for(i=from; i<to; i++){
     aStack[i] = aStack[i+1];
-    zStack[i] = zStack[i+1];
+    if( aStack[i].flags & (STK_Dyn|STK_Static) ){
+      zStack[i] = zStack[i+1];
+    }else{
+      zStack[i] = aStack[i].z;
+    }
   }
   aStack[to] = ts;
-  zStack[to] = tz;
+  if( aStack[to].flags & (STK_Dyn|STK_Static) ){
+    zStack[to] = tz;
+  }else{
+    zStack[to] = aStack[to].z;
+  }
   break;
 }
 
@@ -1230,11 +1259,18 @@ case OP_ColumnName: {
   break;
 }
 
-/* Opcode: Callback P1 * *
+/* Opcode: Callback P1 P2 *
 **
 ** Pop P1 values off the stack and form them into an array.  Then
 ** invoke the callback function using the newly formed array as the
 ** 3rd parameter.
+**
+** If the offset counter (set by the OP_Limit opcode) is positive,
+** then decrement the counter and do not invoke the callback.
+** 
+** If the callback is invoked, then after the callback returns
+** decrement the limit counter.  When the limit counter reaches
+** zero, jump to address P2.
 */
 case OP_Callback: {
   int i = p->tos - pOp->p1 + 1;
@@ -1248,10 +1284,20 @@ case OP_Callback: {
   }
   zStack[p->tos+1] = 0;
   if( xCallback!=0 ){
-    if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
-      rc = SQLITE_ABORT;
+    if( p->iOffset>0 ){
+      p->iOffset--;
+    }else{
+      if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){
+        rc = SQLITE_ABORT;
+      }
+      p->nCallback++;
+      if( p->iLimit>0 ){
+        p->iLimit--;
+        if( p->iLimit==0 ){
+          pc = pOp->p2 - 1;
+        }
+      }
     }
-    p->nCallback++;
   }
   PopStack(p, pOp->p1);
   if( sqlite_malloc_failed ) goto no_mem;
@@ -1462,8 +1508,9 @@ case OP_Precision: {
   int tos = p->tos;
   int nos = tos - 1;
   int nDigit;
+  int len;
   double v;
-  char zBuf[100];
+  char *zNew;
 
   VERIFY( if( nos<0 ) goto not_enough_stack; )
   Realify(p, tos);
@@ -1472,12 +1519,20 @@ case OP_Precision: {
   if( nDigit<0 ) nDigit = 0;
   if( nDigit>30 ) nDigit = 30;
   v = aStack[tos].r;
-  sprintf(zBuf, "%.*f", nDigit, v);
+  zNew = sqlite_mprintf("%.*f", nDigit, v);
+  if( zNew==0 ) goto no_mem;
   POPSTACK;
   Release(p, nos);
-  zStack[nos] = sqliteStrDup(zBuf);
-  aStack[nos].n = strlen(zStack[nos]) + 1;
-  aStack[nos].flags = STK_Str | STK_Dyn;
+  aStack[nos].n = len = strlen(zNew) + 1;
+  if( len<=NBFS ){
+    strcpy(aStack[nos].z, zNew);
+    zStack[nos] = aStack[nos].z;
+    aStack[nos].flags = STK_Str;
+    sqliteFree(zNew);
+  }else{
+    zStack[nos] = zNew;
+    aStack[nos].flags = STK_Str | STK_Dyn;
+  }
   break;
 }
 
@@ -1486,70 +1541,50 @@ case OP_Precision: {
 ** Pop the top two elements from the stack then push back the
 ** largest of the two.
 */
-case OP_Max: {
-  int tos = p->tos;
-  int nos = tos - 1;
-  int ft, fn;
-  int copy = 0;
-  VERIFY( if( nos<0 ) goto not_enough_stack; )
-  ft = aStack[tos].flags;
-  fn = aStack[nos].flags;
-  if( fn & STK_Null ){
-    copy = 1;
-  }else if( (ft & fn & STK_Int)==STK_Int ){
-    copy = aStack[nos].i<aStack[tos].i;
-  }else if( ( (ft|fn) & (STK_Int|STK_Real) ) !=0 ){
-    Realify(p, tos);
-    Realify(p, nos);
-    copy = aStack[tos].r>aStack[nos].r;
-  }else{
-    if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
-    copy = sqliteCompare(zStack[tos],zStack[nos])>0;
-  }
-  if( copy ){
-    Release(p, nos);
-    aStack[nos] = aStack[tos];
-    zStack[nos] = zStack[tos];
-    zStack[tos] = 0;
-    aStack[tos].flags = 0;
-  }else{
-    Release(p, tos);
-  }
-  p->tos = nos;
-  break;
-}
-
 /* Opcode: Min * * *
 **
 ** Pop the top two elements from the stack then push back the
 ** smaller of the two. 
 */
-case OP_Min: {
+case OP_Min:
+case OP_Max: {
   int tos = p->tos;
   int nos = tos - 1;
+  int a,b;
   int ft, fn;
   int copy = 0;
   VERIFY( if( nos<0 ) goto not_enough_stack; )
   ft = aStack[tos].flags;
   fn = aStack[nos].flags;
+  if( pOp->opcode==OP_Max ){
+    a = tos;
+    b = nos;
+  }else{
+    a = nos;
+    b = tos;
+  }
   if( fn & STK_Null ){
     copy = 1;
   }else if( ft & STK_Null ){
     copy = 0;
   }else if( (ft & fn & STK_Int)==STK_Int ){
-    copy = aStack[nos].i>aStack[tos].i;
+    copy = aStack[a].i>aStack[b].i;
   }else if( ( (ft|fn) & (STK_Int|STK_Real) ) !=0 ){
     Realify(p, tos);
     Realify(p, nos);
-    copy = aStack[tos].r<aStack[nos].r;
+    copy = aStack[a].r>aStack[b].r;
   }else{
     if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
-    copy = sqliteCompare(zStack[tos],zStack[nos])<0;
+    copy = sqliteCompare(zStack[a],zStack[b])>0;
   }
   if( copy ){
     Release(p, nos);
     aStack[nos] = aStack[tos];
-    zStack[nos] = zStack[tos];
+    if( aStack[nos].flags & (STK_Dyn|STK_Static) ){
+      zStack[nos] = zStack[tos];
+    }else{
+      zStack[nos] = aStack[nos].z;
+    }
     zStack[tos] = 0;
     aStack[tos].flags = 0;
   }else{
@@ -2016,47 +2051,6 @@ case OP_MakeRecord: {
 **
 ** See also: MakeIdxKey, SortMakeKey
 */
-case OP_MakeKey: {
-  char *zNewKey;
-  int nByte;
-  int nField;
-  int i, j;
-
-  nField = pOp->p1;
-  VERIFY( if( p->tos+1<nField ) goto not_enough_stack; )
-  nByte = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( aStack[i].flags & STK_Null ){
-      nByte++;
-    }else{
-      if( Stringify(p, i) ) goto no_mem;
-      nByte += aStack[i].n;
-    }
-  }
-  if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){
-    rc = SQLITE_TOOBIG;
-    goto abort_due_to_error;
-  }
-  zNewKey = sqliteMalloc( nByte );
-  if( zNewKey==0 ) goto no_mem;
-  j = 0;
-  for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( aStack[i].flags & STK_Null ){
-      zNewKey[j++] = 0;
-    }else{
-      memcpy(&zNewKey[j], zStack[i], aStack[i].n);
-      j += aStack[i].n;
-    }
-  }
-  if( pOp->p2==0 ) PopStack(p, nField);
-  VERIFY( NeedStack(p, p->tos+1); )
-  p->tos++;
-  aStack[p->tos].n = nByte;
-  aStack[p->tos].flags = STK_Str|STK_Dyn;
-  zStack[p->tos] = zNewKey;
-  break;
-}
-
 /* Opcode: MakeIdxKey P1 * *
 **
 ** Convert the top P1 entries of the stack into a single entry suitable
@@ -2075,43 +2069,85 @@ case OP_MakeKey: {
 **
 ** See also:  MakeKey, SortMakeKey
 */
-case OP_MakeIdxKey: {
+case OP_MakeIdxKey:
+case OP_MakeKey: {
   char *zNewKey;
   int nByte;
   int nField;
+  int addRowid;
   int i, j;
-  u32 iKey;
 
+  addRowid = pOp->opcode==OP_MakeIdxKey;
   nField = pOp->p1;
-  VERIFY( if( p->tos+1<nField ) goto not_enough_stack; )
-  nByte = sizeof(u32);
+  VERIFY( if( p->tos+1+addRowid<nField ) goto not_enough_stack; )
+  nByte = 0;
   for(i=p->tos-nField+1; i<=p->tos; i++){
-    if( aStack[i].flags & STK_Null ){
-      nByte++;
+    int flags = aStack[i].flags;
+    int len;
+    char *z;
+    if( flags & STK_Null ){
+      nByte += 2;
+    }else if( flags & STK_Real ){
+      z = aStack[i].z;
+      sqliteRealToSortable(aStack[i].r, &z[1]);
+      z[0] = 0;
+      Release(p, i);
+      len = strlen(&z[1]);
+      zStack[i] = 0;
+      aStack[i].flags = STK_Real;
+      aStack[i].n = len+2;
+      nByte += aStack[i].n;
+    }else if( flags & STK_Int ){
+      z = aStack[i].z;
+      aStack[i].r = aStack[i].i;
+      sqliteRealToSortable(aStack[i].r, &z[1]);
+      z[0] = 0;
+      Release(p, i);
+      len = strlen(&z[1]);
+      zStack[i] = 0;
+      aStack[i].flags = STK_Int;
+      aStack[i].n = len+2;
+      nByte += aStack[i].n;
     }else{
-      if( Stringify(p, i) ) goto no_mem;
+      assert( flags & STK_Str );
+      if( isNumber(zStack[i]) ){
+        aStack[i].r = atof(zStack[i]);
+        Release(p, i);
+        z = aStack[i].z;
+        sqliteRealToSortable(aStack[i].r, &z[1]);
+        z[0] = 0;
+        len = strlen(&z[1]);
+        zStack[i] = 0;
+        aStack[i].flags = STK_Real;
+        aStack[i].n = len+2;
+      }
       nByte += aStack[i].n;
     }
   }
-  if( nByte>MAX_BYTES_PER_ROW ){
+  if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){
     rc = SQLITE_TOOBIG;
     goto abort_due_to_error;
   }
+  if( addRowid ) nByte += sizeof(u32);
   zNewKey = sqliteMalloc( nByte );
   if( zNewKey==0 ) goto no_mem;
   j = 0;
   for(i=p->tos-nField+1; i<=p->tos; i++){
     if( aStack[i].flags & STK_Null ){
       zNewKey[j++] = 0;
+      zNewKey[j++] = 0;
     }else{
-      memcpy(&zNewKey[j], zStack[i], aStack[i].n);
+      memcpy(&zNewKey[j], zStack[i] ? zStack[i] : aStack[i].z, aStack[i].n);
       j += aStack[i].n;
     }
   }
-  Integerify(p, p->tos-nField);
-  iKey = bigEndian(aStack[p->tos-nField].i);
-  memcpy(&zNewKey[j], &iKey, sizeof(u32));
-  PopStack(p, nField+1);
+  if( addRowid ){
+    u32 iKey;
+    Integerify(p, p->tos-nField);
+    iKey = bigEndian(aStack[p->tos-nField].i);
+    memcpy(&zNewKey[j], &iKey, sizeof(u32));
+  }
+  if( pOp->p2==0 ) PopStack(p, nField+addRowid);
   VERIFY( NeedStack(p, p->tos+1); )
   p->tos++;
   aStack[p->tos].n = nByte;
@@ -2686,7 +2722,7 @@ case OP_KeyAsData: {
 ** data.
 */
 case OP_Column: {
-  int amt, offset, end, nCol, payloadSize;
+  int amt, offset, end, payloadSize;
   int i = pOp->p1;
   int p2 = pOp->p2;
   int tos = p->tos+1;
@@ -2750,6 +2786,11 @@ case OP_Column: {
     */
     if( amt==0 ){
       aStack[tos].flags = STK_Null;
+    }else if( amt<=NBFS ){
+      (*xRead)(pCrsr, offset, amt, aStack[tos].z);
+      aStack[tos].flags = STK_Str;
+      zStack[tos] = aStack[tos].z;
+      aStack[tos].n = amt;
     }else{
       char *z = sqliteMalloc( amt );
       if( z==0 ) goto no_mem;
@@ -2815,10 +2856,15 @@ case OP_FullKey: {
       rc = SQLITE_CORRUPT;
       goto abort_due_to_error;
     }
-    z = sqliteMalloc( amt );
+    if( amt>NBFS ){
+      z = sqliteMalloc( amt );
+      aStack[tos].flags = STK_Str | STK_Dyn;
+    }else{
+      z = aStack[tos].z;
+      aStack[tos].flags = STK_Str;
+    }
     sqliteBtreeKey(pCrsr, 0, amt, z);
     zStack[tos] = z;
-    aStack[tos].flags = STK_Str | STK_Dyn;
     aStack[tos].n = amt;
   }
   break;
@@ -3105,6 +3151,25 @@ case OP_Reorganize: {
   break;
 }
 
+/* Opcode:  Limit P1 P2 *
+**
+** Set a limit and offset on callbacks.  P1 is the limit and P2 is
+** the offset.  If the offset counter is positive, no callbacks are
+** invoked but instead the counter is decremented.  Once the offset
+** counter reaches zero, callbacks are invoked and the limit
+** counter is decremented.  When the limit counter reaches zero,
+** the OP_Callback or OP_SortCallback instruction executes a jump
+** that should end the query.
+**
+** This opcode is used to implement the "LIMIT x OFFSET y" clause
+** of a SELECT statement.
+*/
+case OP_Limit: {
+  p->iLimit = pOp->p1;
+  p->iOffset = pOp->p2;
+  break;
+}
+
 /* Opcode: ListWrite * * *
 **
 ** Write the integer on the top of the stack
@@ -3183,7 +3248,8 @@ case OP_ListReset: {
 /* Opcode: SortPut * * *
 **
 ** The TOS is the key and the NOS is the data.  Pop both from the stack
-** and put them on the sorter.
+** and put them on the sorter.  The key and data should have been
+** made using SortMakeKey and SortMakeRec, respectively.
 */
 case OP_SortPut: {
   int tos = p->tos;
@@ -3195,6 +3261,8 @@ case OP_SortPut: {
   if( pSorter==0 ) goto no_mem;
   pSorter->pNext = p->pSort;
   p->pSort = pSorter;
+  assert( aStack[tos].flags & STK_Dyn );
+  assert( aStack[nos].flags & STK_Dyn );
   pSorter->nKey = aStack[tos].n;
   pSorter->zKey = zStack[tos];
   pSorter->nData = aStack[nos].n;
@@ -3359,19 +3427,37 @@ case OP_SortNext: {
   break;
 }
 
-/* Opcode: SortCallback * P2 *
+/* Opcode: SortCallback P1 P2 *
 **
 ** The top of the stack contains a callback record built using
 ** the SortMakeRec operation with the same P1 value as this
 ** instruction.  Pop this record from the stack and invoke the
 ** callback on it.
+**
+** If the offset counter (set by the OP_Limit opcode) is positive,
+** then decrement the counter and do not invoke the callback.
+** 
+** If the callback is invoked, then after the callback returns
+** decrement the limit counter.  When the limit counter reaches
+** zero, jump to address P2.
 */
 case OP_SortCallback: {
   int i = p->tos;
   VERIFY( if( i<0 ) goto not_enough_stack; )
   if( xCallback!=0 ){
-    if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName) ){
-      rc = SQLITE_ABORT;
+    if( p->iOffset>0 ){
+      p->iOffset--;
+    }else{
+      if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){
+        rc = SQLITE_ABORT;
+      }
+      p->nCallback++;
+      if( p->iLimit>0 ){
+        p->iLimit--;
+        if( p->iLimit==0 ){
+          pc = pOp->p2 - 1;
+        }
+      }
     }
     p->nCallback++;
   }
@@ -3413,31 +3499,6 @@ case OP_FileOpen: {
   break;
 }
 
-#if 0 /* NOT USED */
-/* Opcode: FileClose * * *
-**
-** Close a file previously opened using FileOpen.  This is a no-op
-** if there is no prior FileOpen call.
-*/
-case OP_FileClose: {
-  if( p->pFile ){
-    if( p->pFile!=stdin ) fclose(p->pFile);
-    p->pFile = 0;
-  }
-  if( p->azField ){
-    sqliteFree(p->azField);
-    p->azField = 0;
-  }
-  p->nField = 0;
-  if( p->zLine ){
-    sqliteFree(p->zLine);
-    p->zLine = 0;
-  }
-  p->nLineAlloc = 0;
-  break;
-}
-#endif
-
 /* Opcode: FileRead P1 P2 P3
 **
 ** Read a single line of input from the open file (the file opened using
@@ -3561,8 +3622,8 @@ case OP_FileColumn: {
 case OP_MemStore: {
   int i = pOp->p1;
   int tos = p->tos;
-  Mem *pMem;
   char *zOld;
+  Mem *pMem;
   VERIFY( if( tos<0 ) goto not_enough_stack; )
   if( i>=p->nMem ){
     int nOld = p->nMem;
@@ -3582,11 +3643,14 @@ case OP_MemStore: {
     zOld = 0;
   }
   pMem->s = aStack[tos];
-  if( pMem->s.flags & STK_Str ){
-    pMem->z = sqliteStrNDup(zStack[tos], pMem->s.n);
-    pMem->s.flags |= STK_Dyn;
+  if( pMem->s.flags & (STK_Static|STK_Dyn) ){
+    pMem->z = zStack[tos];
+  }else{
+    pMem->z = pMem->s.z;
   }
   if( zOld ) sqliteFree(zOld);
+  zStack[tos] = 0;
+  aStack[tos].flags = 0;
   POPSTACK;
   break;
 }
@@ -3604,12 +3668,16 @@ case OP_MemLoad: {
     zStack[tos] = 0;
   }else{
     aStack[tos] = p->aMem[i].s;
-    if( aStack[tos].flags & STK_Str ){
+    if( aStack[tos].flags & STK_Dyn ){
       char *z = sqliteMalloc(aStack[tos].n);
       if( z==0 ) goto no_mem;
       memcpy(z, p->aMem[i].z, aStack[tos].n);
       zStack[tos] = z;
       aStack[tos].flags |= STK_Dyn;
+    }else if( aStack[tos].flags & STK_Static ){
+      zStack[tos] = p->aMem[i].z;
+    }else if( aStack[tos].flags & STK_Str ){
+      zStack[tos] = aStack[tos].z;
     }
   }
   break;
@@ -3712,12 +3780,14 @@ case OP_AggSet: {
       zOld = 0;
     }
     pMem->s = aStack[tos];
-    if( pMem->s.flags & STK_Str ){
-      pMem->z = sqliteMalloc( aStack[tos].n );
-      if( pMem->z ){
-        memcpy(pMem->z, zStack[tos], pMem->s.n);
-      }
-      pMem->s.flags |= STK_Str|STK_Dyn;
+    if( pMem->s.flags & STK_Dyn ){
+      pMem->z = zStack[tos];
+      zStack[tos] = 0;
+      aStack[tos].flags = 0;
+    }else if( pMem->s.flags & STK_Static ){
+      pMem->z = zStack[tos];
+    }else if( pMem->s.flags & STK_Str ){
+      pMem->z = pMem->s.z;
     }
     if( zOld ) sqliteFree(zOld);
   }
@@ -3772,20 +3842,6 @@ case OP_AggNext: {
   break;
 }
 
-#if 0 /* NOT USED */
-/* Opcode: SetClear P1 * *
-**
-** Remove all elements from the P1-th Set.
-*/
-case OP_SetClear: {
-  int i = pOp->p1;
-  if( i>=0 && i<p->nSet ){
-    sqliteHashClear(&p->aSet[i].hash);
-  }
-  break;
-}
-#endif /* NOT USED */
-
 /* Opcode: SetInsert P1 * P3
 **
 ** If Set P1 does not exist then create it.  Then insert value
index 30d955b784ebe4d57452d881d4e8f13a42f2c206..d835b2a113f92883a01615db228b6ecd7c6be7aa 100644 (file)
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.32 2001/11/04 18:32:48 drh Exp $
+** $Id: vdbe.h,v 1.33 2001/11/06 04:00:19 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -127,74 +127,73 @@ typedef struct VdbeOp VdbeOp;
 #define OP_FileOpen           49
 #define OP_FileRead           50
 #define OP_FileColumn         51
-#define OP_FileClose          52
-
-#define OP_AggReset           53
-#define OP_AggFocus           54
-#define OP_AggIncr            55
-#define OP_AggNext            56
-#define OP_AggSet             57
-#define OP_AggGet             58
-
-#define OP_SetInsert          59
-#define OP_SetFound           60
-#define OP_SetNotFound        61
-#define OP_SetClear           62
-
-#define OP_MakeRecord         63
-#define OP_MakeKey            64
-#define OP_MakeIdxKey         65
-
-#define OP_Goto               66
-#define OP_If                 67
-#define OP_Halt               68
-
-#define OP_ColumnCount        69
-#define OP_ColumnName         70
-#define OP_Callback           71
-#define OP_NullCallback       72
-
-#define OP_Integer            73
-#define OP_String             74
-#define OP_Null               75
-#define OP_Pop                76
-#define OP_Dup                77
-#define OP_Pull               78
-
-#define OP_Add                79
-#define OP_AddImm             80
-#define OP_Subtract           81
-#define OP_Multiply           82
-#define OP_Divide             83
-#define OP_Remainder          84
-#define OP_BitAnd             85
-#define OP_BitOr              86
-#define OP_BitNot             87
-#define OP_ShiftLeft          88
-#define OP_ShiftRight         89
-#define OP_AbsValue           90
-#define OP_Precision          91
-#define OP_Min                92
-#define OP_Max                93
-#define OP_Like               94
-#define OP_Glob               95
-#define OP_Eq                 96
-#define OP_Ne                 97
-#define OP_Lt                 98
-#define OP_Le                 99
-#define OP_Gt                100
-#define OP_Ge                101
-#define OP_IsNull            102
-#define OP_NotNull           103
-#define OP_Negative          104
-#define OP_And               105
-#define OP_Or                106
-#define OP_Not               107
-#define OP_Concat            108
-#define OP_Noop              109
-
-#define OP_Strlen            110
-#define OP_Substr            111
+
+#define OP_AggReset           52
+#define OP_AggFocus           53
+#define OP_AggIncr            54
+#define OP_AggNext            55
+#define OP_AggSet             56
+#define OP_AggGet             57
+
+#define OP_SetInsert          58
+#define OP_SetFound           59
+#define OP_SetNotFound        60
+
+#define OP_MakeRecord         61
+#define OP_MakeKey            62
+#define OP_MakeIdxKey         63
+
+#define OP_Goto               64
+#define OP_If                 65
+#define OP_Halt               66
+
+#define OP_ColumnCount        67
+#define OP_ColumnName         68
+#define OP_Callback           69
+#define OP_NullCallback       70
+
+#define OP_Integer            71
+#define OP_String             72
+#define OP_Pop                73
+#define OP_Dup                74
+#define OP_Pull               75
+
+#define OP_Add                76
+#define OP_AddImm             77
+#define OP_Subtract           78
+#define OP_Multiply           79
+#define OP_Divide             80
+#define OP_Remainder          81
+#define OP_BitAnd             82
+#define OP_BitOr              83
+#define OP_BitNot             84
+#define OP_ShiftLeft          85
+#define OP_ShiftRight         86
+#define OP_AbsValue           87
+#define OP_Precision          88
+#define OP_Min                89
+#define OP_Max                90
+#define OP_Like               91
+#define OP_Glob               92
+#define OP_Eq                 93
+#define OP_Ne                 94
+#define OP_Lt                 95
+#define OP_Le                 96
+#define OP_Gt                 97
+#define OP_Ge                 98
+#define OP_IsNull             99
+#define OP_NotNull           100
+#define OP_Negative          101
+#define OP_And               102
+#define OP_Or                103
+#define OP_Not               104
+#define OP_Concat            105
+#define OP_Noop              106
+
+#define OP_Strlen            107
+#define OP_Substr            108
+
+#define OP_Limit             109
 
 #define OP_MAX               111