]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
rework the VDBE engine. NULL is now distinct from "" (CVS 49)
authordrh <drh@noemail.net>
Sun, 4 Jun 2000 12:58:36 +0000 (12:58 +0000)
committerdrh <drh@noemail.net>
Sun, 4 Jun 2000 12:58:36 +0000 (12:58 +0000)
FossilOrigin-Name: 6ea5cebf05562de00d2cf0b9e2aac5f3857638ee

manifest
manifest.uuid
src/expr.c
src/insert.c
src/select.c
src/shell.c
src/sqliteInt.h
src/tclsqlite.c
src/util.c
src/vdbe.c
src/vdbe.h

index 9a2f3b3c9cd2631dfc5bebbabacb18b3c2268752..2833eb75851f1cb8e66301e19d67055af8226966 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C :-)\s(CVS\s48)
-D 2000-06-03T19:28:49
+C rework\sthe\sVDBE\sengine.\s\sNULL\sis\snow\sdistinct\sfrom\s""\s(CVS\s49)
+D 2000-06-04T12:58:37
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
 F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -10,20 +10,20 @@ F src/build.c 15c4f3844774baa882435223119a18c33810ee94
 F src/dbbe.c ae8b5d2cdb4fa7dd11313059984be9457fa77f63
 F src/dbbe.h a8a46f71238e0f09f3ec08fd9d1c8c7f4cdc49bf
 F src/delete.c e11433c14ed5cc8553cba14296b3baa3c23054bc
-F src/expr.c 6df33b3a42039e1eb1eb556c84a4b190a8eca8ca
-F src/insert.c 62951015437a96d388f43b591437d489719872fb
+F src/expr.c 793c15de4ce2911fa1a74999750bd3c0c9ca513f
+F src/insert.c ddae33b3dea1b4e743092d04240a20def9f88b72
 F src/main.c ed15e0132659ace7f44ea2dbcdd21c232af3dbd5
 F src/parse.y 9ec486608b7b4daaccf4ad9f05eef1a26a008fb8
-F src/select.c 2f4ae48deae2c5c94a89b3bc4fef2fe96c575e9f
-F src/shell.c bd658f9208bc20ce565c3f687836155772ca939a
+F src/select.c 2dff3d237db6588ad657bb13f19dedebc046a4eb
+F src/shell.c d184aeae4b14d469da1fb09f7899c27367a67dc6
 F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
-F src/sqliteInt.h 606a1614000f4e1cf208fe656bfabc5bd2957c7e
-F src/tclsqlite.c 10c00c460246cfba375b768c90b22bfe3c774c8f
+F src/sqliteInt.h da9749098da8c3537175e637179ca456709aee53
+F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
 F src/tokenize.c 15c229fee77325334c6814652e429b0930eba6c1
 F src/update.c 3f05d5082fd2c34f15d1e4a4db17355ad8807a78
-F src/util.c c22846f23b9311ca0e68f076686493bac7b20d5d
-F src/vdbe.c a584da66af8b44b0236bece378c4dc8ef333f814
-F src/vdbe.h ab574c91c6328c5795f68b84074fbcf860eae70e
+F src/util.c a06e8379665b18539cd9400641f3581d925f337e
+F src/vdbe.c 35e1c8fce3e5a5e59f493b1fe9a4f6f6a3205585
+F src/vdbe.h f20a3140905c385237e0891122beccde779c78c7
 F src/where.c bed9a8360cbfbf712bdc397c8e22216a5e5f9800
 F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
 F test/copy.test 6b218a41dc6469491049b50ee105f76282f2547d
@@ -47,7 +47,7 @@ F www/c_interface.tcl 8867d76ddd416d2fbd41e4cb3de8efa9cef105a5
 F www/changes.tcl 567cc6066d87460bdedff8e5bbc20f41ddaadf77
 F www/index.tcl f8189a7898f6d06307c34047b9d7e00860026e44
 F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd
-P 729d6586b8377d0e6cefa64c8cf3d883e9f0ddc3
-R 31c9e39e649b3b2d917f87f2b14771de
+P f76656416500851069633cc603905befa27cca66
+R dca222cd1ac9b9199dff323c95ec2e9d
 U drh
-Z 40d2fc5da1772ef64d963d97198b5963
+Z 114e443f09135bb7212679d2a361e0f5
index be1180821e59a25b95e024ddfa60146ee8cd5df6..b0e5125e04c9162f6a17c2f04b1533a159bbfdd6 100644 (file)
@@ -1 +1 @@
-f76656416500851069633cc603905befa27cca66
\ No newline at end of file
+6ea5cebf05562de00d2cf0b9e2aac5f3857638ee
\ No newline at end of file
index 78feb8f539b8d80895b5152e4528bcad727ac600..a993834969c2d4eaee9ff2f748de1af2b4ef6bce 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** This file contains C code routines used for processing expressions
 **
-** $Id: expr.c,v 1.4 2000/06/03 19:19:41 drh Exp $
+** $Id: expr.c,v 1.5 2000/06/04 12:58:37 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -324,7 +324,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
       break;
     }
     case TK_NULL: {
-      sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+      sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
       break;
     }
     case TK_AND:
index f9478203207857eb0abe599dd7408e93a98f3357..24fcff6705b5cc632e09e7988b16e7a33669a7f6 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements.
 **
-** $Id: insert.c,v 1.4 2000/06/03 18:06:53 drh Exp $
+** $Id: insert.c,v 1.5 2000/06/04 12:58:38 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -122,8 +122,11 @@ void sqliteInsert(
       }
       if( pField && j>=pField->nId ){
         char *zDflt = pTab->aCol[i].zDflt;
-        if( zDflt==0 ) zDflt = "";
-        sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0);
+        if( zDflt==0 ){
+          sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
+        }else{
+          sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0);
+        }
       }else{
         sqliteExprCode(pParse, pList->a[j].pExpr);
       }
@@ -146,8 +149,11 @@ void sqliteInsert(
         }
         if( pField && j>=pField->nId ){
           char *zDflt = pTab->aCol[idx].zDflt;
-          if( zDflt==0 ) zDflt = "";
-          sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0);
+          if( zDflt==0 ){
+            sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
+          }else{
+            sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0);
+          }
         }else{
           sqliteExprCode(pParse, pList->a[j].pExpr);
         }
index 561a5fb8ae74ee24da9d5fb5c2b7cc4f4fe92fed..82001ea18fd6b9fabca9b3bf1c5de8c26f85ffa3 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements.
 **
-** $Id: select.c,v 1.5 2000/06/03 18:06:53 drh Exp $
+** $Id: select.c,v 1.6 2000/06/04 12:58:38 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -183,7 +183,7 @@ void sqliteSelect(
       switch( sqliteFuncId(&p->token) ){
         case FN_Min:
         case FN_Max: {
-          sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+          sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
           break;
         }
         default: {
@@ -251,6 +251,7 @@ void sqliteSelect(
       }
       if( id!=FN_Count && p->pList && p->pList->nExpr>=1 ){
         sqliteExprCode(pParse, p->pList->a[0].pExpr);
+        sqliteVdbeAddOp(v, OP_Concat, 1, 0, 0, 0);
       }
       switch( sqliteFuncId(&p->token) ){
         case FN_Count: op = OP_AddImm; p1 = 1; break;
index 25214012194e3437b868496796dab3cec66253da..81b2b5c8c9ef04b13db09e20647a9c711be0e220 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.6 2000/06/02 13:27:59 drh Exp $
+** $Id: shell.c,v 1.7 2000/06/04 12:58:38 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -154,7 +154,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
     case MODE_Line: {
       if( p->cnt++>0 ) fprintf(p->out,"\n");
       for(i=0; i<nArg; i++){
-        fprintf(p->out,"%s = %s\n", azCol[i], azArg[i]);
+        fprintf(p->out,"%s = %s\n", azCol[i], azArg[i] ? azArg[i] : 0);
       }
       break;
     }
@@ -188,7 +188,8 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
         }else{
            w = 10;
         }
-        fprintf(p->out,"%-*.*s%s",w,w,azArg[i], i==nArg-1 ? "\n": "  ");
+        fprintf(p->out,"%-*.*s%s",w,w,
+            azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": "  ");
       }
       break;
     }
@@ -199,7 +200,8 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
         }
       }
       for(i=0; i<nArg; i++){
-        fprintf(p->out,"%s%s",azArg[i], i==nArg-1 ? "\n" : p->separator);
+        fprintf(p->out,"%s%s",azArg[i] ? azArg[i] : "",
+             i==nArg-1 ? "\n" : p->separator);
       }
       break;
     }
@@ -214,7 +216,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
       for(i=0; i<nArg; i++){
         fprintf(p->out,"<TR>");
         for(i=0; i<nArg; i++){
-          fprintf(p->out,"<TD>%s</TD>",azArg[i]);
+          fprintf(p->out,"<TD>%s</TD>",azArg[i] ? azArg[i] : "");
         }
         fprintf(p->out,"</TD>\n");
       }
index f59fdbf0d4635fbe4b31ef18f73288100c85402c..45625a532e3d96fe5ebd32cf86434ebc73ab90d5 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.11 2000/06/03 18:06:53 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.12 2000/06/04 12:58:38 drh Exp $
 */
 #include "sqlite.h"
 #include "dbbe.h"
@@ -35,7 +35,7 @@
 #include <string.h>
 #include <assert.h>
 
-/* #define MEMORY_DEBUG 2 */
+#define MEMORY_DEBUG 1
 #ifdef MEMORY_DEBUG
 # define sqliteMalloc(X)    sqliteMalloc_(X,__FILE__,__LINE__)
 # define sqliteFree(X)      sqliteFree_(X,__FILE__,__LINE__)
index 1499cf6e272adb6d6d4149de448161bc9ff67556..e3e88d0bc5744ca138b3a5a2f65a7cf60aaceb18 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.4 2000/06/02 01:17:38 drh Exp $
+** $Id: tclsqlite.c,v 1.5 2000/06/04 12:58:38 drh Exp $
 */
 #include "sqlite.h"
 #include <tcl.h>
@@ -61,11 +61,15 @@ static int DbEvalCallback(
       }
     }
     for(i=0; i<nCol; i++){
-      Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], azCol[i], 0);
+      char *z = azCol[i];
+      if( z==0 ) z = "";
+      Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0);
     }
   }else{
     for(i=0; i<nCol; i++){
-      Tcl_SetVar(cbData->interp, azN[i], azCol[i], 0);
+      char *z = azCol[i];
+      if( z==0 ) z = "";
+      Tcl_SetVar(cbData->interp, azN[i], z, 0);
     }
   }
   cbData->once = 0;
@@ -283,9 +287,9 @@ int TCLSH_MAIN(int argc, char **argv){
           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
     }
     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
-      fprintf(stderr,"%s: %s\n", *argv, 
-         Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)
-      );
+      char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
+      if( zInfo==0 ) zInfo = interp->result;
+      fprintf(stderr,"%s: %s\n", *argv, zInfo);
       return 1;
     }
   }else{
index d8a68f2a3bfb194c3e2ccca1fe5da4f72363207e..1142a60e9af19ba5f4cd7404f33c48967f683192 100644 (file)
@@ -26,7 +26,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.9 2000/06/02 13:28:00 drh Exp $
+** $Id: util.c,v 1.10 2000/06/04 12:58:38 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -632,6 +632,7 @@ int sqliteGlobCompare(const char *zPattern, const char *zString){
         }else{
           while( (c2 = *zString)!=0 ){
             while( c2 != 0 && c2 != c ){ c2 = *++zString; }
+            if( c2==0 ) return 0;
             if( sqliteGlobCompare(&zPattern[1],zString) ) return 1;
             zString++;
           }
@@ -699,6 +700,7 @@ sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
         }else{
           while( (c2 = UpperToLower[*zString])!=0 ){
             while( c2 != 0 && c2 != c ){ c2 = UpperToLower[*++zString]; }
+            if( c2==0 ) return 0;
             if( sqliteLikeCompare(&zPattern[1],zString) ) return 1;
             zString++;
           }
index 836d550d73ccc4a0b2125bf4fe92be19ffdb39d9..22eea0ca0ecfb1b97ebbca9cbd25da9a89e30666 100644 (file)
@@ -41,7 +41,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.12 2000/06/02 23:22:40 drh Exp $
+** $Id: vdbe.c,v 1.13 2000/06/04 12:58:38 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -80,6 +80,30 @@ struct Sorter {
 */
 #define NSORT 30
 
+/*
+** A single level of the stack is an instance of the following
+** structure.  Except, string values are stored on a separate
+** list of of pointers to character.  The reason for storing
+** strings separately is so that they can be easily passed
+** to the callback function.
+*/
+struct Stack {
+  int i;         /* Integer value */
+  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 */      
+};
+typedef struct Stack Stack;
+
+/*
+** Allowed values for Stack.flags
+*/
+#define STK_Null      0x0001   /* Value is NULL */
+#define STK_Str       0x0002   /* Value is a string */
+#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[*] */
+
 /*
 ** An instance of the virtual machine
 */
@@ -94,7 +118,7 @@ struct Vdbe {
   int *aLabel;        /* Space to hold the labels */
   int tos;            /* Index of top of stack */
   int nStackAlloc;    /* Size of the stack */
-  int *iStack;        /* Integer values of the stack */
+  Stack *aStack;      /* The operand stack, except string values */
   char **zStack;      /* Text or binary values of the stack */
   char **azColName;   /* Becomes the 4th parameter to callbacks */
   int nTable;         /* Number of slots in aTab[] */
@@ -290,6 +314,86 @@ int sqliteVdbeMakeLabel(Vdbe *p){
   return -1-i;
 }
 
+/*
+** Convert the given stack entity into a string if it isn't one
+** already.  Return non-zero if we run out of memory.
+**
+** NULLs are converted into an empty string.
+*/
+#define Stringify(P,I) \
+   ((P->aStack[I].flags & STK_Str)==0 ? hardStringify(P,I) : 0)
+static int hardStringify(Vdbe *p, int i){
+  char zBuf[30];
+  int fg = p->aStack[i].flags;
+  if( fg & STK_Real ){
+    sprintf(zBuf,"%g",p->aStack[i].r);
+  }else if( fg & STK_Int ){
+    sprintf(zBuf,"%d",p->aStack[i].i);
+  }else{
+    p->zStack[i] = "";
+    p->aStack[i].n = 1;
+    p->aStack[i].flags |= STK_Str;
+    return 0;
+  }
+  p->zStack[i] = 0;
+  sqliteSetString(&p->zStack[i], zBuf, 0);
+  if( p->zStack[i]==0 ) return 1;
+  p->aStack[i].n = strlen(p->zStack[i])+1;
+  p->aStack[i].flags |= STK_Str|STK_Dyn;
+  return 0;
+}
+
+/*
+** Release the memory associated with the given stack level
+*/
+#define Release(P,I)  if((P)->aStack[I].flags&STK_Dyn){ hardRelease(P,I); }
+static void hardRelease(Vdbe *p, int i){
+  sqliteFree(p->zStack[i]);
+  p->zStack[i] = 0;
+  p->aStack[i].flags &= ~(STK_Str|STK_Dyn);
+}
+
+/*
+** Convert the given stack entity into a integer if it isn't one
+** already.
+**
+** Any prior string or real representation is invalidated.  
+** NULLs are converted into 0.
+*/
+#define Integerify(P,I) \
+    if(((P)->aStack[(I)].flags&STK_Int)==0){ hardIntegerify(P,I); }
+static void hardIntegerify(Vdbe *p, int i){
+  if( p->aStack[i].flags & STK_Real ){
+    p->aStack[i].i = p->aStack[i].r;
+    Release(p, i);
+  }else if( p->aStack[i].flags & STK_Str ){
+    p->aStack[i].i = atoi(p->zStack[i]);
+    Release(p, i);
+  }else{
+    p->aStack[i].i = 0;
+  }
+  p->aStack[i].flags = STK_Int;
+}
+
+/*
+** Get a valid Real representation for the given stack element.
+**
+** Any prior string or integer representation is retained.
+** NULLs are converted into 0.0.
+*/
+#define Realify(P,I) \
+    if(((P)->aStack[(I)].flags&STK_Real)==0){ hardRealify(P,I); }
+static void hardRealify(Vdbe *p, int i){
+  if( p->aStack[i].flags & STK_Str ){
+    p->aStack[i].r = atof(p->zStack[i]);
+  }else if( p->aStack[i].flags & STK_Int ){
+    p->aStack[i].r = p->aStack[i].i;
+  }else{
+    p->aStack[i].r = 0.0;
+  }
+  p->aStack[i].flags |= STK_Real;
+}
+
 /*
 ** Pop the stack N times.  Free any memory associated with the
 ** popped stack elements.
@@ -298,11 +402,47 @@ static void PopStack(Vdbe *p, int N){
   if( p->zStack==0 ) return;
   while( p->tos>=0 && N-->0 ){
     int i = p->tos--;
-    sqliteFree(p->zStack[i]);
+    if( p->aStack[i].flags & STK_Dyn ){
+      sqliteFree(p->zStack[i]);
+    }
+    p->aStack[i].flags = 0;
     p->zStack[i] = 0;
   }    
 }
 
+/*
+** Make sure space has been allocated to hold at least N
+** stack elements.  Allocate additional stack space if
+** necessary.
+**
+** Return 0 on success and non-zero if there are memory
+** allocation errors.
+*/
+#define NeedStack(P,N) (((P)->nStackAlloc<=(N)) ? hardNeedStack(P,N) : 0)
+static int hardNeedStack(Vdbe *p, int N){
+  int oldAlloc;
+  int i;
+  if( N>=p->nStackAlloc ){
+    oldAlloc = p->nStackAlloc;
+    p->nStackAlloc = N + 20;
+    p->aStack = sqliteRealloc(p->aStack, p->nStackAlloc*sizeof(p->aStack[0]));
+    p->zStack = sqliteRealloc(p->zStack, p->nStackAlloc*sizeof(char*));
+    if( p->aStack==0 || p->zStack==0 ){
+      sqliteFree(p->aStack);
+      sqliteFree(p->zStack);
+      p->aStack = 0;
+      p->zStack = 0;
+      p->nStackAlloc = 0;
+      return 1;
+    }
+    for(i=oldAlloc; i<p->nStackAlloc; i++){
+      p->zStack[i] = 0;
+      p->aStack[i].flags = 0;
+    }
+  }
+  return 0;
+}
+
 /*
 ** Clean up the VM after execution.
 **
@@ -376,7 +516,7 @@ void sqliteVdbeDelete(Vdbe *p){
   }
   sqliteFree(p->aOp);
   sqliteFree(p->aLabel);
-  sqliteFree(p->iStack);
+  sqliteFree(p->aStack);
   sqliteFree(p->zStack);
   sqliteFree(p);
 }
@@ -402,13 +542,13 @@ static char *zOpName[] = { 0,
   "FileRead",       "FileField",      "FileClose",      "MakeRecord",
   "MakeKey",        "Goto",           "If",             "Halt",
   "ColumnCount",    "ColumnName",     "Callback",       "Integer",
-  "String",         "Pop",            "Dup",            "Pull",
-  "Add",            "AddImm",         "Subtract",       "Multiply",
-  "Divide",         "Min",            "Max",            "Like",
-  "Glob",           "Eq",             "Ne",             "Lt",
-  "Le",             "Gt",             "Ge",             "IsNull",
-  "NotNull",        "Negative",       "And",            "Or",
-  "Not",            "Concat",         "Noop",         
+  "String",         "Null",           "Pop",            "Dup",
+  "Pull",           "Add",            "AddImm",         "Subtract",
+  "Multiply",       "Divide",         "Min",            "Max",
+  "Like",           "Glob",           "Eq",             "Ne",
+  "Lt",             "Le",             "Gt",             "Ge",
+  "IsNull",         "NotNull",        "Negative",       "And",
+  "Or",             "Not",            "Concat",         "Noop",
 };
 
 /*
@@ -459,7 +599,6 @@ int sqliteVdbeList(
     sprintf(zP1,"%d", p->aOp[i].p1);
     sprintf(zP2,"%d", p->aOp[i].p2);
     azField[4] = p->aOp[i].p3;
-    if( azField[4]==0 ) azField[4] = "";
     azField[1] = zOpName[p->aOp[i].opcode];
     if( xCallback(pArg, 5, azField, azColumnNames) ){
       rc = SQLITE_ABORT;
@@ -468,65 +607,6 @@ int sqliteVdbeList(
   return rc;
 }
 
-/*
-** Make sure space has been allocated to hold at least N
-** stack elements.  Allocate additional stack space if
-** necessary.
-**
-** Return 0 on success and non-zero if there are memory
-** allocation errors.
-*/
-static int NeedStack(Vdbe *p, int N){
-  int oldAlloc;
-  int i;
-  if( N>=p->nStackAlloc ){
-    oldAlloc = p->nStackAlloc;
-    p->nStackAlloc = N + 20;
-    p->iStack = sqliteRealloc(p->iStack, p->nStackAlloc*sizeof(int));
-    p->zStack = sqliteRealloc(p->zStack, p->nStackAlloc*sizeof(char*));
-    if( p->iStack==0 || p->zStack==0 ){
-      sqliteFree(p->iStack);
-      sqliteFree(p->zStack);
-      p->iStack = 0;
-      p->zStack = 0;
-      p->nStackAlloc = 0;
-      return 1;
-    }
-    for(i=oldAlloc; i<p->nStackAlloc; i++){
-      p->zStack[i] = 0;
-    }
-  }
-  return 0;
-}
-
-/*
-** Convert the given stack entity into a string if it isn't one
-** already.  Return non-zero if we run out of memory.
-*/
-static int Stringify(Vdbe *p, int i){
-  if( p->zStack[i]==0 ){
-    char zBuf[30];
-    sprintf(zBuf,"%d",p->iStack[i]);
-    sqliteSetString(&p->zStack[i], zBuf, 0);
-    if( p->zStack[i]==0 ) return 1;
-    p->iStack[i] = strlen(p->zStack[i])+1;
-  }
-  return 0;
-}
-
-/*
-** Convert the given stack entity into a integer if it isn't one
-** already.
-*/
-static int Integerify(Vdbe *p, int i){
-  if( p->zStack[i]!=0 ){
-    p->iStack[i] = atoi(p->zStack[i]);
-    sqliteFree(p->zStack[i]);
-    p->zStack[i] = 0;
-  }
-  return p->iStack[i];
-}
-
 /*
 ** The parameters are pointers to the head of two sorted lists
 ** of Sorter structures.  Merge these two lists together and return
@@ -629,8 +709,8 @@ int sqliteVdbeExec(
       case OP_Integer: {
         int i = ++p->tos;
         if( NeedStack(p, p->tos) ) goto no_mem;
-        p->iStack[i] = pOp->p1;
-        p->zStack[i] = 0;
+        p->aStack[i].i = pOp->p1;
+        p->aStack[i].flags = STK_Int;
         break;
       }
 
@@ -644,8 +724,22 @@ int sqliteVdbeExec(
         if( NeedStack(p, p->tos) ) goto no_mem;
         z = pOp->p3;
         if( z==0 ) z = "";
-        p->iStack[i] = strlen(z) + 1;
-        sqliteSetString(&p->zStack[i], z, 0);
+        p->zStack[i] = z;
+        p->aStack[i].n = strlen(z) + 1;
+        p->aStack[i].flags = STK_Str;
+        break;
+      }
+
+      /* Opcode: NULL * * *
+      **
+      ** Push a NULL value onto the stack.
+      */
+      case OP_Null: {
+        int i = ++p->tos;
+        char *z;
+        if( NeedStack(p, p->tos) ) goto no_mem;
+        p->zStack[i] = 0;
+        p->aStack[i].flags = STK_Null;
         break;
       }
 
@@ -671,19 +765,20 @@ int sqliteVdbeExec(
         int j = ++p->tos;
         if( i<0 ) goto not_enough_stack;
         if( NeedStack(p, p->tos) ) goto no_mem;
-        p->iStack[j] = p->iStack[i];
-        if( p->zStack[i] ){
-          p->zStack[j] = sqliteMalloc( p->iStack[j] );
-          if( p->zStack[j] ) memcpy(p->zStack[j], p->zStack[i], p->iStack[j]);
+        p->aStack[j] = p->aStack[i];
+        if( p->aStack[i].flags & STK_Dyn ){
+          p->zStack[j] = sqliteMalloc( p->aStack[j].n );
+          if( p->zStack[j]==0 ) goto no_mem;
+          memcpy(p->zStack[j], p->zStack[i], p->aStack[j].n);
         }else{
-          p->zStack[j] = 0;
+          p->zStack[j] = p->zStack[i];
         }
         break;
       }
 
       /* Opcode: Pull P1 * *
       **
-      ** The P1-th element is removed its current location on 
+      ** The P1-th element is removed from its current location on 
       ** the stack and pushed back on top of the stack.  The
       ** top of the stack is element 0, so "Pull 0 0 0" is
       ** a no-op.
@@ -692,16 +787,16 @@ int sqliteVdbeExec(
         int from = p->tos - pOp->p1;
         int to = p->tos;
         int i;
-        int ti;
+        Stack ts;
         char *tz;
         if( from<0 ) goto not_enough_stack;
-        ti = p->iStack[from];
+        ts = p->aStack[from];
         tz = p->zStack[from];
         for(i=from; i<to; i++){
-          p->iStack[i] = p->iStack[i+1];
+          p->aStack[i] = p->aStack[i+1];
           p->zStack[i] = p->zStack[i+1];
         }
-        p->iStack[to] = ti;
+        p->aStack[to] = ts;
         p->zStack[to] = tz;
         break;
       }
@@ -744,7 +839,9 @@ int sqliteVdbeExec(
         if( i<0 ) goto not_enough_stack;
         if( NeedStack(p, p->tos+2) ) goto no_mem;
         for(j=i; j<=p->tos; j++){
-          if( Stringify(p, j) ) goto no_mem;
+          if( (p->aStack[j].flags & STK_Null)==0 ){
+            if( Stringify(p, j) ) goto no_mem;
+          }
         }
         p->zStack[p->tos+1] = 0;
         if( xCallback!=0 ){
@@ -756,25 +853,59 @@ int sqliteVdbeExec(
         break;
       }
 
-      /* Opcode: Concat * * *
+      /* Opcode: Concat P1 P2 P3
+      **
+      ** Look at the first P1 elements of the stack.  Append them all 
+      ** together with the lowest element first.  Use P3 as a separator.  
+      ** Put the result on the top of the stack.  The original P1 elements
+      ** are popped from the stack if P2==0 and retained if P2==1.
       **
-      ** Pop two elements from the stack.  Append the first (what used
-      ** to be the top of stack) to the second (the next on stack) to 
-      ** form a new string.  Push the new string back onto the stack.
+      ** If P3 is NULL, then use no separator.  When P1==1, this routine
+      ** makes a copy of the top stack element into memory obtained
+      ** from sqliteMalloc().
       */
       case OP_Concat: {
-        int tos = p->tos;
-        int nos = tos - 1;
-        char *z;
-        if( nos<0 ) goto not_enough_stack;
-        Stringify(p, tos);
-        Stringify(p, nos);
-        z = 0;
-        sqliteSetString(&z, p->zStack[nos], p->zStack[tos], 0);
-        PopStack(p, 1);
-        sqliteFree(p->zStack[nos]);
-        p->zStack[nos] = z;
-        p->iStack[nos] = strlen(p->zStack[nos])+1;
+        char *zNew;
+        int nByte;
+        int nField;
+        int i, j;
+        char *zSep;
+        int nSep;
+
+        nField = pOp->p1;
+        zSep = pOp->p3;
+        if( zSep==0 ) zSep = "";
+        nSep = strlen(zSep);
+        if( p->tos+1<nField ) goto not_enough_stack;
+        nByte = 1 - nSep;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( p->aStack[i].flags & STK_Null ){
+            nByte += nSep;
+          }else{
+            if( Stringify(p, i) ) goto no_mem;
+            nByte += p->aStack[i].n - 1 + nSep;
+          }
+        }
+        zNew = sqliteMalloc( nByte );
+        if( zNew==0 ) goto no_mem;
+        j = 0;
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( (p->aStack[i].flags & STK_Null)==0 ){
+            memcpy(&zNew[j], p->zStack[i], p->aStack[i].n-1);
+            j += p->aStack[i].n-1;
+          }
+          if( nSep>0 && i<p->tos ){
+            memcpy(&zNew[j], zSep, nSep);
+            j += nSep;
+          }
+        }
+        zNew[j] = 0;
+        if( pOp->p2==0 ) PopStack(p, nField);
+        NeedStack(p, p->tos+1);
+        p->tos++;
+        p->aStack[p->tos].n = nByte;
+        p->aStack[p->tos].flags = STK_Str|STK_Dyn;
+        p->zStack[p->tos] = zNew;
         break;
       }
 
@@ -818,10 +949,10 @@ int sqliteVdbeExec(
         int tos = p->tos;
         int nos = tos - 1;
         if( nos<0 ) goto not_enough_stack;
-        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
+        if( (p->aStack[tos].flags & p->aStack[nos].flags & STK_Int)==STK_Int ){
           int a, b;
-          a = p->iStack[tos];
-          b = p->iStack[nos];
+          a = p->aStack[tos].i;
+          b = p->aStack[nos].i;
           switch( pOp->opcode ){
             case OP_Add:         b += a;       break;
             case OP_Subtract:    b -= a;       break;
@@ -836,14 +967,16 @@ int sqliteVdbeExec(
               break;
             }
           }
-          PopStack(p, 1);
-          p->iStack[nos] = b;
+          PopStack(p, 2);
+          p->tos = nos;
+          p->aStack[nos].i = b;
+          p->aStack[nos].flags = STK_Int;
         }else{
           double a, b;
-          Stringify(p, tos);
-          Stringify(p, nos);
-          a = atof(p->zStack[tos]);
-          b = atof(p->zStack[nos]);
+          Realify(p, tos);
+          Realify(p, nos);
+          a = p->aStack[tos].r;
+          b = p->aStack[nos].r;
           switch( pOp->opcode ){
             case OP_Add:         b += a;       break;
             case OP_Subtract:    b -= a;       break;
@@ -858,11 +991,10 @@ int sqliteVdbeExec(
               break;
             }
           }
-          sprintf(zBuf,"%g",b);
           PopStack(p, 1);
-          sqliteSetString(&p->zStack[nos], zBuf, 0);
-          if( p->zStack[nos]==0 ) goto no_mem;
-          p->iStack[nos] = strlen(p->zStack[nos]) + 1;
+          Release(p, nos);
+          p->aStack[nos].r = b;
+          p->aStack[nos].flags = STK_Real;
         }
         break;
       }
@@ -875,22 +1007,34 @@ int sqliteVdbeExec(
       case OP_Max: {
         int tos = p->tos;
         int nos = tos - 1;
+        int ft, fn;
+        int copy = 0;
         if( nos<0 ) goto not_enough_stack;
-        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
-          if( p->iStack[nos]<p->iStack[tos] ){
-            p->iStack[nos] = p->iStack[tos];
-          }
+        ft = p->aStack[tos].flags;
+        fn = p->aStack[nos].flags;
+        if( fn & STK_Null ){
+          copy = 1;
+        }else if( (ft & fn & STK_Int)==STK_Int ){
+          copy = p->aStack[nos].i<p->aStack[tos].i;
+        }else if( ( (ft|fn) & (STK_Int|STK_Real) ) !=0 ){
+          Realify(p, tos);
+          Realify(p, nos);
+          copy = p->aStack[tos].r>p->aStack[nos].r;
         }else{
           Stringify(p, tos);
           Stringify(p, nos);
-          if( sqliteCompare(p->zStack[nos], p->zStack[tos])<0 ){
-            sqliteFree(p->zStack[nos]);
-            p->zStack[nos] = p->zStack[tos];
-            p->iStack[nos] = p->iStack[tos];
-            p->zStack[tos] = 0;
-          }
+          copy = sqliteCompare(p->zStack[tos],p->zStack[nos])>0;
+        }
+        if( copy ){
+          Release(p, nos);
+          p->aStack[nos] = p->aStack[tos];
+          p->zStack[nos] = p->zStack[tos];
+          p->zStack[tos] = 0;
+          p->aStack[tos].flags = 0;
+        }else{
+          Release(p, tos);
         }
-        p->tos--;
+        p->tos = nos;
         break;
       }
 
@@ -905,28 +1049,37 @@ int sqliteVdbeExec(
       case OP_Min: {
         int tos = p->tos;
         int nos = tos - 1;
+        int ft, fn;
+        int copy = 0;
         if( nos<0 ) goto not_enough_stack;
-        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
-          if( p->iStack[nos]>p->iStack[tos] ){
-            p->iStack[nos] = p->iStack[tos];
-          }
+        ft = p->aStack[tos].flags;
+        fn = p->aStack[nos].flags;
+        if( pOp->p1 ){
+          copy = 1;
+          pOp->p1 = 0;
+        }else if( fn & STK_Null ){
+          copy = 1;
+        }else if( (ft & fn & STK_Int)==STK_Int ){
+          copy = p->aStack[nos].i>p->aStack[tos].i;
+        }else if( ( (ft|fn) & (STK_Int|STK_Real) ) !=0 ){
+          Realify(p, tos);
+          Realify(p, nos);
+          copy = p->aStack[tos].r<p->aStack[nos].r;
         }else{
           Stringify(p, tos);
           Stringify(p, nos);
-          if( pOp->p1==1 ){
-            sqliteFree(p->zStack[nos]);
-            p->zStack[nos] = p->zStack[tos];
-            p->iStack[nos] = p->iStack[tos];
-            p->zStack[tos] = 0;
-            pOp->p1 = 0;
-          }else if( sqliteCompare(p->zStack[nos], p->zStack[tos])>0 ){
-            sqliteFree(p->zStack[nos]);
-            p->zStack[nos] = p->zStack[tos];
-            p->iStack[nos] = p->iStack[tos];
-            p->zStack[tos] = 0;
-          }
+          copy = sqliteCompare(p->zStack[tos],p->zStack[nos])<0;
+        }
+        if( copy ){
+          Release(p, nos);
+          p->aStack[nos] = p->aStack[tos];
+          p->zStack[nos] = p->zStack[tos];
+          p->zStack[tos] = 0;
+          p->aStack[tos].flags = 0;
+        }else{
+          Release(p, tos);
         }
-        p->tos--;
+        p->tos = nos;
         break;
       }
 
@@ -938,7 +1091,7 @@ int sqliteVdbeExec(
         int tos = p->tos;
         if( tos<0 ) goto not_enough_stack;
         Integerify(p, tos);
-        p->iStack[tos] += pOp->p1;
+        p->aStack[tos].i += pOp->p1;
         break;
       }
 
@@ -986,31 +1139,24 @@ int sqliteVdbeExec(
         int tos = p->tos;
         int nos = tos - 1;
         int c;
+        int ft, fn;
         if( nos<0 ) goto not_enough_stack;
-        if( p->zStack[tos]==0 && p->zStack[nos]==0 ){
-          int a, b;
-          a = p->iStack[tos];
-          b = p->iStack[nos];
-          switch( pOp->opcode ){
-            case OP_Eq:    c = b==a;     break;
-            case OP_Ne:    c = b!=a;     break;
-            case OP_Lt:    c = b<a;      break;
-            case OP_Le:    c = b<=a;     break;
-            case OP_Gt:    c = b>a;      break;
-            default:       c = b>=a;     break;
-          }
+        ft = p->aStack[tos].flags;
+        fn = p->aStack[nos].flags;
+        if( (ft & fn)==STK_Int ){
+          c = p->aStack[nos].i - p->aStack[tos].i;
         }else{
           Stringify(p, tos);
           Stringify(p, nos);
           c = sqliteCompare(p->zStack[nos], p->zStack[tos]);
-          switch( pOp->opcode ){
-            case OP_Eq:    c = c==0;     break;
-            case OP_Ne:    c = c!=0;     break;
-            case OP_Lt:    c = c<0;      break;
-            case OP_Le:    c = c<=0;     break;
-            case OP_Gt:    c = c>0;      break;
-            default:       c = c>=0;     break;
-          }
+        }
+        switch( pOp->opcode ){
+          case OP_Eq:    c = c==0;     break;
+          case OP_Ne:    c = c!=0;     break;
+          case OP_Lt:    c = c<0;      break;
+          case OP_Le:    c = c<=0;     break;
+          case OP_Gt:    c = c>0;      break;
+          default:       c = c>=0;     break;
         }
         PopStack(p, 2);
         if( c ) pc = pOp->p2-1;
@@ -1082,53 +1228,55 @@ int sqliteVdbeExec(
       **
       ** Pop two values off the stack.  Take the logical AND of the
       ** two values and push the resulting boolean value back onto the
-      ** stack.  Integers are considered false if zero and true otherwise.
-      ** Strings are considered false if their length is zero and true
-      ** otherwise.
+      ** stack. 
       */
       /* Opcode: Or * * *
       **
       ** Pop two values off the stack.  Take the logical OR of the
       ** two values and push the resulting boolean value back onto the
-      ** stack.  Integers are considered false if zero and true otherwise.
-      ** Strings are considered false if their length is zero and true
-      ** otherwise.
+      ** stack. 
       */
       case OP_And:
       case OP_Or: {
         int tos = p->tos;
         int nos = tos - 1;
-        int x, y, c;
+        int c;
         if( nos<0 ) goto not_enough_stack;
-        x = p->zStack[nos] ? p->zStack[nos][0] : p->iStack[nos];
-        y = p->zStack[tos] ? p->zStack[tos][0] : p->iStack[tos];
+        Integerify(p, tos);
+        Integerify(p, nos);
         if( pOp->opcode==OP_And ){
-          c = x && y;
+          c = p->aStack[tos].i && p->aStack[nos].i;
         }else{
-          c = x || y;
+          c = p->aStack[tos].i || p->aStack[nos].i;
         }
         PopStack(p, 2);
         p->tos++;
-        p->iStack[nos] = c;
+        p->aStack[nos].i = c;
+        p->aStack[nos].flags = STK_Int;
         break;
       }
 
       /* Opcode: Negative * * *
       **
       ** Treat the top of the stack as a numeric quantity.  Replace it
-      ** with its additive inverse.  If the top of stack is a string,
-      ** then it is converted into a number using atof().
+      ** with its additive inverse.
       */
       case OP_Negative: {
         int tos;
         if( (tos = p->tos)<0 ) goto not_enough_stack;
-        if( p->zStack[tos] ){
-          double r = atof(p->zStack[tos]);
-          sprintf(zBuf, "%g", -r);
-          sqliteSetString(&p->zStack[tos], zBuf, 0);
-          p->iStack[tos] = strlen(zBuf) + 1;
+        if( p->aStack[tos].flags & STK_Real ){
+          Release(p, tos);
+          p->aStack[tos].r = -p->aStack[tos].r;
+          p->aStack[tos].flags = STK_Real;
+        }else if( p->aStack[tos].flags & STK_Int ){
+          Release(p, tos);
+          p->aStack[tos].i = -p->aStack[tos].i;
+          p->aStack[tos].flags = STK_Int;
         }else{
-          p->iStack[tos] = -p->iStack[tos];
+          Realify(p, tos);
+          Release(p, tos);
+          p->aStack[tos].r = -p->aStack[tos].r;
+          p->aStack[tos].flags = STK_Real;
         }
         break;
       }
@@ -1136,16 +1284,15 @@ int sqliteVdbeExec(
       /* Opcode: Not * * *
       **
       ** Treat the top of the stack as a boolean value.  Replace it
-      ** with its complement.  Integers are false if zero and true
-      ** otherwise.  Strings are false if zero-length and true otherwise.
+      ** with its complement.
       */
       case OP_Not: {
-        int c;
+        int tos = p->tos;
         if( p->tos<0 ) goto not_enough_stack;
-        c = p->zStack[p->tos] ? p->zStack[p->tos][0] : p->iStack[p->tos];
-        PopStack(p, 1);
-        p->tos++;
-        p->iStack[p->tos] = !c;
+        Integerify(p, tos);
+        Release(p, tos);
+        p->aStack[tos].i = !p->aStack[tos].i;
+        p->aStack[tos].flags = STK_Int;
         break;
       }
 
@@ -1168,7 +1315,8 @@ int sqliteVdbeExec(
       case OP_If: {
         int c;
         if( p->tos<0 ) goto not_enough_stack;
-        c = p->zStack[p->tos] ? p->zStack[p->tos][0] : p->iStack[p->tos];
+        Integerify(p, p->tos);
+        c = p->aStack[p->tos].i;
         PopStack(p, 1);
         if( c ) pc = pOp->p2-1;
         break;
@@ -1176,14 +1324,14 @@ int sqliteVdbeExec(
 
       /* Opcode: IsNull * P2 *
       **
-      ** Pop a single value from the stack.  If the value popped is the
-      ** empty string, then jump to p2.  Otherwise continue to the next 
+      ** Pop a single value from the stack.  If the value popped is NULL
+      ** then jump to p2.  Otherwise continue to the next 
       ** instruction.
       */
       case OP_IsNull: {
         int c;
         if( p->tos<0 ) goto not_enough_stack;
-        c = p->zStack[p->tos]!=0 && p->zStack[p->tos][0]==0;
+        c = (p->aStack[p->tos].flags & STK_Null)!=0;
         PopStack(p, 1);
         if( c ) pc = pOp->p2-1;
         break;
@@ -1198,7 +1346,7 @@ int sqliteVdbeExec(
       case OP_NotNull: {
         int c;
         if( p->tos<0 ) goto not_enough_stack;
-        c = p->zStack[p->tos]==0 || p->zStack[p->tos][0]!=0;
+        c = (p->aStack[p->tos].flags & STK_Null)==0;
         PopStack(p, 1);
         if( c ) pc = pOp->p2-1;
         break;
@@ -1208,14 +1356,15 @@ int sqliteVdbeExec(
       **
       ** Convert the top P1 entries of the stack into a single entry
       ** suitable for use as a data record in the database.  To do this
-      ** each entry is converted to a string and all the strings are
+      ** all entries (except NULLs) are converted to strings and 
       ** concatenated.  The null-terminators are preserved by the concatation
       ** and serve as a boundry marker between fields.  The lowest entry
       ** on the stack is the first in the concatenation and the top of
       ** the stack is the last.  After all fields are concatenated, an
       ** index header is added.  The index header consists of P1 integers
       ** which hold the offset of the beginning of each field from the
-      ** beginning of the completed record including the header.
+      ** beginning of the completed record including the header.  The
+      ** index for NULL entries is 0.
       */
       case OP_MakeRecord: {
         char *zNewRecord;
@@ -1228,29 +1377,37 @@ int sqliteVdbeExec(
         if( p->tos+1<nField ) goto not_enough_stack;
         nByte = 0;
         for(i=p->tos-nField+1; i<=p->tos; i++){
-          if( Stringify(p, i) ) goto no_mem;
-          nByte += p->iStack[i];
+          if( (p->aStack[i].flags & STK_Null)==0 ){
+            if( Stringify(p, i) ) goto no_mem;
+            nByte += p->aStack[i].n;
+          }
         }
         nByte += sizeof(int)*nField;
         zNewRecord = sqliteMalloc( nByte );
         if( zNewRecord==0 ) goto no_mem;
         j = 0;
         addr = sizeof(int)*nField;
-        for(i=p->tos-nField+1; i<p->tos; i++){
-          memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
-          addr += p->iStack[i];
+        for(i=p->tos-nField+1; i<=p->tos; i++){
+          if( p->aStack[i].flags & STK_Null ){
+            int zero = 0;
+            memcpy(&zNewRecord[j], (char*)&zero, sizeof(int));
+          }else{
+            memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
+            addr += p->aStack[i].n;
+          }
           j += sizeof(int);
         }
-        memcpy(&zNewRecord[j], (char*)&addr, sizeof(int));
-        j += sizeof(int);
         for(i=p->tos-nField+1; i<=p->tos; i++){
-          memcpy(&zNewRecord[j], p->zStack[i], p->iStack[i]);
-          j += p->iStack[i];
+          if( (p->aStack[i].flags & STK_Null)==0 ){
+            memcpy(&zNewRecord[j], p->zStack[i], p->aStack[i].n);
+            j += p->aStack[i].n;
+          }
         }
         PopStack(p, nField);
         NeedStack(p, p->tos+1);
         p->tos++;
-        p->iStack[p->tos] = nByte;
+        p->aStack[p->tos].n = nByte;
+        p->aStack[p->tos].flags = STK_Str | STK_Dyn;
         p->zStack[p->tos] = zNewRecord;
         break;
       }
@@ -1281,22 +1438,29 @@ int sqliteVdbeExec(
         if( p->tos+1<nField ) goto not_enough_stack;
         nByte = 0;
         for(i=p->tos-nField+1; i<=p->tos; i++){
-          if( Stringify(p, i) ) goto no_mem;
-          nByte += p->iStack[i]+1;
+          if( p->aStack[i].flags & STK_Null ){
+            nByte++;
+          }else{
+            if( Stringify(p, i) ) goto no_mem;
+            nByte += p->aStack[i].n;
+          }
         }
         zNewKey = sqliteMalloc( nByte );
         if( zNewKey==0 ) goto no_mem;
         j = 0;
         for(i=p->tos-nField+1; i<=p->tos; i++){
-          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
-          j += p->iStack[i]-1;
+          if( (p->aStack[i].flags & STK_Null)==0 ){
+            memcpy(&zNewKey[j], p->zStack[i], p->aStack[i].n-1);
+            j += p->aStack[i].n-1;
+          }
           if( i<p->tos ) zNewKey[j++] = '\t';
         }
         zNewKey[j] = 0;
         if( pOp->p2==0 ) PopStack(p, nField);
         NeedStack(p, p->tos+1);
         p->tos++;
-        p->iStack[p->tos] = nByte;
+        p->aStack[p->tos].n = nByte;
+        p->aStack[p->tos].flags = STK_Str|STK_Dyn;
         p->zStack[p->tos] = zNewKey;
         break;
       }
@@ -1311,6 +1475,8 @@ int sqliteVdbeExec(
       ** the VDBE finishes execution.  The P1 values need not be
       ** contiguous but all P1 values should be small integers.  It is
       ** an error for P1 to be negative.
+      **
+      ** If P3 is null or an empty string, a temporary table is opened.
       */
       case OP_Open: {
         int i = pOp->p1;
@@ -1374,11 +1540,12 @@ int sqliteVdbeExec(
         int tos = p->tos;
         if( tos<0 ) goto not_enough_stack;
         if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
-          if( p->zStack[tos]==0 ){
+          if( p->aStack[tos].flags & STK_Int ){
             sqliteDbbeFetch(p->aTab[i].pTable, sizeof(int), 
-                           (char*)&p->iStack[tos]);
+                           (char*)&p->aStack[tos].i);
           }else{
-            sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], 
+            if( Stringify(p, tos) ) goto no_mem;
+            sqliteDbbeFetch(p->aTab[i].pTable, p->aStack[tos].n, 
                            p->zStack[tos]);
           }
         }
@@ -1399,11 +1566,12 @@ int sqliteVdbeExec(
         int alreadyExists = 0;
         if( tos<0 ) goto not_enough_stack;
         if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
-          if( p->zStack[tos]==0 ){
+          if( p->aStack[tos].flags & STK_Int ){
             alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, sizeof(int), 
-                                          (char*)&p->iStack[tos]);
+                                          (char*)&p->aStack[tos].i);
           }else{
-            alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, p->iStack[tos], 
+            if( Stringify(p, tos) ) goto no_mem;
+            alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, p->aStack[tos].n, 
                                            p->zStack[tos]);
           }
         }
@@ -1428,7 +1596,8 @@ int sqliteVdbeExec(
         }
         NeedStack(p, p->tos+1);
         p->tos++;
-        p->iStack[p->tos] = v;
+        p->aStack[p->tos].i = v;
+        p->aStack[p->tos].flags = STK_Int;
         break;
       }
 
@@ -1448,16 +1617,16 @@ int sqliteVdbeExec(
         if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
           char *zKey;
           int nKey;
-          Stringify(p, tos);
-          if( p->zStack[nos]!=0 ){
-            nKey = p->iStack[nos];
+          if( (p->aStack[nos].flags & STK_Int)==0 ){
+            if( Stringify(p, nos) ) goto no_mem;
+            nKey = p->aStack[nos].n;
             zKey = p->zStack[nos];
           }else{
             nKey = sizeof(int);
-            zKey = (char*)&p->iStack[nos];
+            zKey = (char*)&p->aStack[nos].i;
           }
           sqliteDbbePut(p->aTab[i].pTable, nKey, zKey,
-                        p->iStack[tos], p->zStack[tos]);
+                        p->aStack[tos].n, p->zStack[tos]);
         }
         PopStack(p, 2);
         break;
@@ -1475,12 +1644,13 @@ int sqliteVdbeExec(
         if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
           char *zKey;
           int nKey;
-          if( p->zStack[tos]!=0 ){
-            nKey = p->iStack[tos];
+          if( (p->aStack[tos].flags & STK_Int)==0 ){
+            if( Stringify(p, tos) ) goto no_mem;
+            nKey = p->aStack[tos].n;
             zKey = p->zStack[tos];
           }else{
             nKey = sizeof(int);
-            zKey = (char*)&p->iStack[tos];
+            zKey = (char*)&p->aStack[tos].n;
           }
           sqliteDbbeDelete(p->aTab[i].pTable, nKey, zKey);
         }
@@ -1492,6 +1662,11 @@ int sqliteVdbeExec(
       **
       ** Push onto the stack the value of the P2-th field from the
       ** most recent Fetch from table P1.
+      ** 
+      ** The value pushed is just a pointer to the data in the cursor.
+      ** The value will go away the next time a record is fetched from P1,
+      ** or when P1 is closed.  Make a copy of the string if it needs
+      ** to persist longer than that.
       */
       case OP_Field: {
         int *pAddr;
@@ -1502,17 +1677,21 @@ int sqliteVdbeExec(
         DbbeTable *pTab;
         char *z;
 
-        if( NeedStack(p, p->tos) ) goto no_mem;
+        if( NeedStack(p, tos) ) goto no_mem;
         if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
           amt = sqliteDbbeDataLength(pTab);
           if( amt<=sizeof(int)*(p2+1) ){
-            sqliteSetString(&p->zStack[tos], "", 0);
+            p->aStack[tos].flags = STK_Null;
             break;
           }
           pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2);
-          z = sqliteDbbeReadData(pTab, *pAddr);
-          sqliteSetString(&p->zStack[tos], z, 0);
-          p->iStack[tos] = strlen(z)+1;
+          if( *pAddr==0 ){
+            p->aStack[tos].flags = STK_Null;
+            break;
+          }
+          p->zStack[tos] = z = sqliteDbbeReadData(pTab, *pAddr);
+          p->aStack[tos].n = strlen(z) + 1;
+          p->aStack[tos].flags = STK_Str;
         }
         break;
       }
@@ -1531,8 +1710,8 @@ int sqliteVdbeExec(
         if( NeedStack(p, p->tos) ) goto no_mem;
         if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
           char *z = sqliteDbbeReadKey(pTab, 0);
-          memcpy(&p->iStack[tos], z, sizeof(int));
-          p->zStack[tos] = 0;
+          memcpy(&p->aStack[tos].i, z, sizeof(int));
+          p->aStack[tos].flags = STK_Int;
         }
         break;
       }
@@ -1599,7 +1778,8 @@ int sqliteVdbeExec(
           aIdx = (int*)sqliteDbbeReadData(pTab, 0);
           for(j=p->aTab[i].index; j<nIdx; j++){
             if( aIdx[j]!=0 ){
-              p->iStack[tos] = aIdx[j];
+              p->aStack[tos].i = aIdx[j];
+              p->aStack[tos].flags = STK_Int;
               break;
             }
           }
@@ -1630,12 +1810,14 @@ int sqliteVdbeExec(
         if( nos<0 ) goto not_enough_stack;
         if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){
           int r;
-          int newVal = Integerify(p, nos);
-          Stringify(p, tos);
-          r = sqliteDbbeFetch(pTab, p->iStack[tos], p->zStack[tos]);
+          int newVal;
+          Integerify(p, nos);
+          newVal = p->aStack[nos].i;
+          if( Stringify(p, tos) ) goto no_mem;
+          r = sqliteDbbeFetch(pTab, p->aStack[tos].n, p->zStack[tos]);
           if( r==0 ){
             /* Create a new record for this index */
-            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos],
+            sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos],
                           sizeof(int), (char*)&newVal);
           }else{
             /* Extend the existing record */
@@ -1646,7 +1828,7 @@ int sqliteVdbeExec(
             if( aIdx==0 ) goto no_mem;
             sqliteDbbeCopyData(pTab, 0, nIdx*sizeof(int), (char*)aIdx);
             aIdx[nIdx] = newVal;
-            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos],
+            sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos],
                           sizeof(int)*(nIdx+1), (char*)aIdx);
             sqliteFree(aIdx);
           }
@@ -1675,9 +1857,11 @@ int sqliteVdbeExec(
           int nIdx;
           int j;
           int r;
-          int oldVal = Integerify(p, nos);
-          Stringify(p, tos);
-          r = sqliteDbbeFetch(pTab, p->iStack[tos], p->zStack[tos]);
+          int oldVal;
+          Integerify(p, nos);
+          oldVal = p->aStack[nos].i;
+          if( Stringify(p, tos) ) goto no_mem;
+          r = sqliteDbbeFetch(pTab, p->aStack[tos].n, p->zStack[tos]);
           if( r==0 ) break;
           nIdx = sqliteDbbeDataLength(pTab)/sizeof(int);
           aIdx = (int*)sqliteDbbeReadData(pTab, 0);
@@ -1685,9 +1869,9 @@ int sqliteVdbeExec(
           if( j>=nIdx ) break;
           aIdx[j] = aIdx[nIdx-1];
           if( nIdx==1 ){
-            sqliteDbbeDelete(pTab, p->iStack[tos], p->zStack[tos]);
+            sqliteDbbeDelete(pTab, p->aStack[tos].n, p->zStack[tos]);
           }else{
-            sqliteDbbePut(pTab, p->iStack[tos], p->zStack[tos], 
+            sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos], 
                           sizeof(int)*(nIdx-1), (char*)aIdx);
           }
         }
@@ -1751,7 +1935,9 @@ int sqliteVdbeExec(
         if( i<0 ) goto bad_instruction;
         if( p->tos<0 ) goto not_enough_stack;
         if( i<p->nList && p->apList[i]!=0 ){
-          int val = Integerify(p, p->tos);
+          int val;
+          Integerify(p, p->tos);
+          val = p->aStack[p->tos].i;
           PopStack(p, 1);
           fwrite(&val, sizeof(int), 1, p->apList[i]);
         }
@@ -1785,8 +1971,8 @@ int sqliteVdbeExec(
         if( amt==1 ){
           p->tos++;
           if( NeedStack(p, p->tos) ) goto no_mem;
-          p->iStack[p->tos] = val;
-          p->zStack[p->tos] = 0;
+          p->aStack[p->tos].n = val;
+          p->aStack[p->tos].flags = STK_Int;
         }else{
           pc = pOp->p2 - 1;
         }
@@ -1831,21 +2017,25 @@ int sqliteVdbeExec(
       */
       case OP_SortPut: {
         int i = pOp->p1;
+        int tos = p->tos;
+        int nos = tos - 1;
         Sorter *pSorter;
         if( i<0 || i>=p->nSort ) goto bad_instruction;
-        if( p->tos<1 ) goto not_enough_stack;
-        Stringify(p, p->tos);
-        Stringify(p, p->tos-1);
+        if( tos<1 ) goto not_enough_stack;
+        if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
         pSorter = sqliteMalloc( sizeof(Sorter) );
         if( pSorter==0 ) goto no_mem;
         pSorter->pNext = p->apSort[i];
         p->apSort[i] = pSorter;
-        pSorter->nKey = p->iStack[p->tos];
-        pSorter->zKey = p->zStack[p->tos];
-        pSorter->nData = p->iStack[p->tos-1];
-        pSorter->pData = p->zStack[p->tos-1];
-        p->zStack[p->tos] = p->zStack[p->tos-1] = 0;
-        PopStack(p, 2);
+        pSorter->nKey = p->aStack[tos].n;
+        pSorter->zKey = p->zStack[tos];
+        pSorter->nData = p->aStack[nos].n;
+        pSorter->pData = p->zStack[nos];
+        p->aStack[tos].flags = 0;
+        p->aStack[nos].flags = 0;
+        p->zStack[tos] = 0;
+        p->zStack[nos] = 0;
+        p->tos -= 2;
         break;
       }
 
@@ -1866,23 +2056,30 @@ int sqliteVdbeExec(
         if( p->tos+1<nField ) goto not_enough_stack;
         nByte = 0;
         for(i=p->tos-nField+1; i<=p->tos; i++){
-          if( Stringify(p, i) ) goto no_mem;
-          nByte += p->iStack[i];
+          if( (p->aStack[i].flags & STK_Null)==0 ){
+            if( Stringify(p, i) ) goto no_mem;
+            nByte += p->aStack[i].n;
+          }
         }
         nByte += sizeof(char*)*(nField+1);
         azArg = sqliteMalloc( nByte );
         if( azArg==0 ) goto no_mem;
         z = (char*)&azArg[nField+1];
         for(j=0, i=p->tos-nField+1; i<=p->tos; i++, j++){
-          azArg[j] = z;
-          strcpy(z, p->zStack[i]);
-          z += p->iStack[i];
+          if( p->aStack[i].flags & STK_Null ){
+            azArg[j] = 0;
+          }else{
+            azArg[j] = z;
+            strcpy(z, p->zStack[i]);
+            z += p->aStack[i].n;
+          }
         }
         PopStack(p, nField);
         NeedStack(p, p->tos+1);
         p->tos++;
-        p->iStack[p->tos] = nByte;
+        p->aStack[p->tos].n = nByte;
         p->zStack[p->tos] = (char*)azArg;
+        p->aStack[p->tos].flags = STK_Str|STK_Dyn;
         break;
       }
 
@@ -1910,7 +2107,7 @@ int sqliteVdbeExec(
         nByte = 1;
         for(i=p->tos-nField+1; i<=p->tos; i++){
           if( Stringify(p, i) ) goto no_mem;
-          nByte += p->iStack[i]+2;
+          nByte += p->aStack[i].n+2;
         }
         zNewKey = sqliteMalloc( nByte );
         if( zNewKey==0 ) goto no_mem;
@@ -1918,15 +2115,16 @@ int sqliteVdbeExec(
         k = nField-1;
         for(i=p->tos-nField+1; i<=p->tos; i++){
           zNewKey[j++] = pOp->p3[k--];
-          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
-          j += p->iStack[i]-1;
+          memcpy(&zNewKey[j], p->zStack[i], p->aStack[i].n-1);
+          j += p->aStack[i].n-1;
           zNewKey[j++] = 0;
         }
         zNewKey[j] = 0;
         PopStack(p, nField);
         NeedStack(p, p->tos+1);
         p->tos++;
-        p->iStack[p->tos] = nByte;
+        p->aStack[p->tos].n = nByte;
+        p->aStack[p->tos].flags = STK_Str|STK_Dyn;
         p->zStack[p->tos] = zNewKey;
         break;
       }
@@ -1987,7 +2185,8 @@ int sqliteVdbeExec(
           p->tos++;
           NeedStack(p, p->tos);
           p->zStack[p->tos] = pSorter->pData;
-          p->iStack[p->tos] = pSorter->nData;
+          p->aStack[p->tos].n = pSorter->nData;
+          p->aStack[p->tos].flags = STK_Str|STK_Dyn;
           sqliteFree(pSorter->zKey);
           sqliteFree(pSorter);
         }else{
@@ -2009,7 +2208,8 @@ int sqliteVdbeExec(
           p->tos++;
           NeedStack(p, p->tos);
           sqliteSetString(&p->zStack[p->tos], pSorter->zKey, 0);
-          p->iStack[p->tos] = pSorter->nKey;
+          p->aStack[p->tos].n = pSorter->nKey;
+          p->aStack[p->tos].flags = STK_Str|STK_Dyn;
         }
         break;
       }
@@ -2190,8 +2390,9 @@ int sqliteVdbeExec(
         }
         if( z==0 ) z = "";
         p->tos++;
-        p->iStack[p->tos] = strlen(z) + 1;
-        sqliteSetString(&p->zStack[p->tos], z, 0);
+        p->aStack[p->tos].n = strlen(z) + 1;
+        p->zStack[p->tos] = z;
+        p->aStack[p->tos].flags = STK_Str;
         break;
       }
 
@@ -2212,10 +2413,20 @@ int sqliteVdbeExec(
       int i;
       fprintf(p->trace, "Stack:");
       for(i=p->tos; i>=0 && i>p->tos-5; i--){
-        if( p->zStack[i] ){
-          fprintf(p->trace, " [%.11s]", p->zStack[i]);
+        if( p->aStack[i].flags & STK_Null ){
+          fprintf(p->trace, " NULL");
+        }else if( p->aStack[i].flags & STK_Int ){
+          fprintf(p->trace, " i:%d", p->aStack[i].i);
+        }else if( p->aStack[i].flags & STK_Real ){
+          fprintf(p->trace, " r:%g", p->aStack[i].r);
+        }else if( p->aStack[i].flags & STK_Str ){
+          if( p->aStack[i].flags & STK_Dyn ){
+            fprintf(p->trace, " z:[%.11s]", p->zStack[i]);
+          }else{
+            fprintf(p->trace, " s:[%.11s]", p->zStack[i]);
+          }
         }else{
-          fprintf(p->trace, " [%d]", p->iStack[i]);
+          fprintf(p->trace, " ???");
         }
       }
       fprintf(p->trace,"\n");
index 9a01412a10454388b1fb070297363556c7e828ad..3abba05695eabb6d20af4f3e778991b9df857b52 100644 (file)
@@ -27,7 +27,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.4 2000/05/31 20:00:53 drh Exp $
+** $Id: vdbe.h,v 1.5 2000/06/04 12:58:39 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -125,35 +125,36 @@ typedef struct VdbeOp VdbeOp;
 
 #define OP_Integer            44
 #define OP_String             45
-#define OP_Pop                46
-#define OP_Dup                47
-#define OP_Pull               48
-
-#define OP_Add                49
-#define OP_AddImm             50
-#define OP_Subtract           51
-#define OP_Multiply           52
-#define OP_Divide             53
-#define OP_Min                54
-#define OP_Max                55
-#define OP_Like               56
-#define OP_Glob               57
-#define OP_Eq                 58
-#define OP_Ne                 59
-#define OP_Lt                 60
-#define OP_Le                 61
-#define OP_Gt                 62
-#define OP_Ge                 63
-#define OP_IsNull             64
-#define OP_NotNull            65
-#define OP_Negative           66
-#define OP_And                67
-#define OP_Or                 68
-#define OP_Not                69
-#define OP_Concat             70
-#define OP_Noop               71
-
-#define OP_MAX                71
+#define OP_Null               46
+#define OP_Pop                47
+#define OP_Dup                48
+#define OP_Pull               49
+
+#define OP_Add                50
+#define OP_AddImm             51
+#define OP_Subtract           52
+#define OP_Multiply           53
+#define OP_Divide             54
+#define OP_Min                55
+#define OP_Max                56
+#define OP_Like               57
+#define OP_Glob               58
+#define OP_Eq                 59
+#define OP_Ne                 60
+#define OP_Lt                 61
+#define OP_Le                 62
+#define OP_Gt                 63
+#define OP_Ge                 64
+#define OP_IsNull             65
+#define OP_NotNull            66
+#define OP_Negative           67
+#define OP_And                68
+#define OP_Or                 69
+#define OP_Not                70
+#define OP_Concat             71
+#define OP_Noop               72
+
+#define OP_MAX                72
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation