From 9a32464b543cda85c698bd14e3561c4ebff22da1 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 6 Sep 2003 20:12:01 +0000 Subject: [PATCH] Split almost 1300 lines of code out of vdbe.c into separate files vdbeInt.h and vdbeaux.c. (CVS 1094) FossilOrigin-Name: bfd69391d3d63675f206ffd8ff0401ea1cbcc073 --- main.mk | 21 +- manifest | 16 +- manifest.uuid | 2 +- src/vdbe.c | 1327 ++----------------------------------------------- src/vdbeInt.h | 297 +++++++++++ src/vdbeaux.c | 996 +++++++++++++++++++++++++++++++++++++ 6 files changed, 1353 insertions(+), 1306 deletions(-) create mode 100644 src/vdbeInt.h create mode 100644 src/vdbeaux.c diff --git a/main.mk b/main.mk index b70f591fc2..2aa68497cb 100644 --- a/main.mk +++ b/main.mk @@ -58,7 +58,7 @@ LIBOBJ = attach.o auth.o btree.o btree_rb.o build.o copy.o delete.o \ expr.o func.o hash.o insert.o \ main.o opcodes.o os.o pager.o parse.o pragma.o printf.o random.o \ select.o table.o tokenize.o trigger.o update.o util.o \ - vacuum.o vdbe.o where.o tclsqlite.o + vacuum.o vdbe.o vdbeaux.o where.o tclsqlite.o # All of the source code files. # @@ -97,6 +97,8 @@ SRC = \ $(TOP)/src/vacuum.c \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbe.h \ + $(TOP)/src/vdbeaux.c \ + $(TOP)/src/vdbeInt.h \ $(TOP)/src/where.c # Source code to the test files. @@ -121,9 +123,15 @@ HDR = \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/sqliteInt.h \ - $(TOP)/src/vdbe.h \ + $(TOP)/src/vdbe.h \ parse.h +# Header files used by the VDBE submodule +# +VDBEHDR = \ + $(HDR) \ + $(TOP)/src/vdbeInt.h + # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # @@ -150,10 +158,10 @@ sqlite$(EXE): $(TOP)/src/shell.c libsqlite.a sqlite.h # files are automatically generated. This target takes care of # all that automatic generation. # -target_source: $(SRC) $(HDR) opcodes.c +target_source: $(SRC) $(VDBEHDR) opcodes.c rm -rf tsrc mkdir tsrc - cp $(SRC) $(HDR) tsrc + cp $(SRC) $(VDBEHDR) tsrc rm tsrc/sqlite.h.in tsrc/parse.y cp parse.c opcodes.c tsrc @@ -239,9 +247,12 @@ util.o: $(TOP)/src/util.c $(HDR) vacuum.o: $(TOP)/src/vacuum.c $(HDR) $(TCCX) -c $(TOP)/src/vacuum.c -vdbe.o: $(TOP)/src/vdbe.c $(HDR) +vdbe.o: $(TOP)/src/vdbe.c $(VDBEHDR) $(TCCX) -c $(TOP)/src/vdbe.c +vdbeaux.o: $(TOP)/src/vdbeaux.c $(VDBEHDR) + $(TCCX) -c $(TOP)/src/vdbeaux.c + where.o: $(TOP)/src/where.c $(HDR) $(TCCX) -c $(TOP)/src/where.c diff --git a/manifest b/manifest index b041b4fb83..b17a98bdc9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sbeginnings\sof\schanges\sto\ssupport\spre-compiled\sSQL.\s\sMostly\suntested,\nthough\sall\sregression\stests\sto\spass.\s(CVS\s1093) -D 2003-09-06T01:10:47 +C Split\salmost\s1300\slines\sof\scode\sout\sof\svdbe.c\sinto\sseparate\sfiles\nvdbeInt.h\sand\svdbeaux.c.\s(CVS\s1094) +D 2003-09-06T20:12:01 F Makefile.in f7e916ae863393827fa6a4cb292e3398096edcf1 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -16,7 +16,7 @@ F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F libtool bbbea7d79c23323e4100103836028e4fad0d9242 F ltmain.sh abfb9387049fff6996afc6e325736597795baf11 -F main.mk d01843179ed14559adb75f7e2fe093c943d56756 +F main.mk 6af144bac62d83899b71919c738fdf442a4f1c16 F publish.sh 86b5e8535830a2588f62ce1d5d1ef00e1dede23a F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea @@ -61,8 +61,10 @@ F src/trigger.c 474581eaab388233df01bb019e558af2965decbf F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397 F src/util.c f16efa2d60bfd4e31ae06b07ed149557e828d294 F src/vacuum.c e4724eade07e4cf8897060a8cf632dbd92408eeb -F src/vdbe.c b6a2b0a8eeca95cc29a9e07fb7d2cc3c1eaec468 +F src/vdbe.c 00c547e77d4100b6671c1509df5993ab315a166c F src/vdbe.h 3c51cb382316dbf3860e4ece72e658b4bf014501 +F src/vdbeInt.h 15cd01061b2f0acb967bdc5195fe1e891bb707a1 +F src/vdbeaux.c ebf5eab163fa8435e4fc24bcebe4eab4147d871b F src/where.c 83b2a2d26d5c3bea33457a83e541bb1dcf7b1248 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test c26848402e7ac829e043e1fa5e0eb87032e5d81d @@ -170,7 +172,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P aaa84c6202f6e16828bcd6aff2e424f3dba1f82b -R 0bb0019009c0a448d322679ad1dd5f73 +P 912f47c72d3597c6d5acff765d94922bd660339a +R 197956f145d2d77ab02def05dccb6402 U drh -Z 42cb329fb1ec590b60ca4f6b47463c49 +Z 7934264d068323cc21204d69f10c800f diff --git a/manifest.uuid b/manifest.uuid index b0c5bbb28c..f05e5965d6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -912f47c72d3597c6d5acff765d94922bd660339a \ No newline at end of file +bfd69391d3d63675f206ffd8ff0401ea1cbcc073 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index de33d162d7..305168dfca 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -9,7 +9,14 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** The code in this file implements the Virtual Database Engine (VDBE) +** The code in this file implements execution method of the +** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c") +** handles housekeeping details such as creating and deleting +** VDBE instances. This file is solely interested in executing +** the VDBE program. +** +** In the external interface, an "sqlite_vm*" is an opaque pointer +** to a VDBE. ** ** The SQL parser generates a program which is then executed by ** the VDBE to do the work of the SQL statement. VDBE programs are @@ -36,19 +43,12 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.238 2003/09/06 01:10:48 drh Exp $ +** $Id: vdbe.c,v 1.239 2003/09/06 20:12:01 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include - -/* -** The makefile scans this source file and creates the following -** array of string constants which are the names of all VDBE opcodes. -** This array is defined in a separate source code file named opcode.c -** which is automatically generated by the makefile. -*/ -extern char *sqliteOpcodeNames[]; +#include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor @@ -59,700 +59,6 @@ extern char *sqliteOpcodeNames[]; */ int sqlite_search_count = 0; -/* -** SQL is translated into a sequence of instructions to be -** executed by a virtual machine. Each instruction is an instance -** of the following structure. -*/ -typedef struct VdbeOp Op; - -/* -** Boolean values -*/ -typedef unsigned char Bool; - -/* -** A cursor is a pointer into a single BTree within a database file. -** The cursor can seek to a BTree entry with a particular key, or -** loop over all entries of the Btree. You can also insert new BTree -** entries or retrieve the key or data from the entry that the cursor -** is currently pointing to. -** -** Every cursor that the virtual machine has open is represented by an -** instance of the following structure. -** -** If the Cursor.isTriggerRow flag is set it means that this cursor is -** really a single row that represents the NEW or OLD pseudo-table of -** a row trigger. The data for the row is stored in Cursor.pData and -** the rowid is in Cursor.iKey. -*/ -struct Cursor { - BtCursor *pCursor; /* The cursor structure of the backend */ - int lastRecno; /* Last recno from a Next or NextIdx operation */ - int nextRowid; /* Next rowid returned by OP_NewRowid */ - Bool recnoIsValid; /* True if lastRecno is valid */ - Bool keyAsData; /* The OP_Column command works on key instead of data */ - Bool atFirst; /* True if pointing to first entry */ - Bool useRandomRowid; /* Generate new record numbers semi-randomly */ - Bool nullRow; /* True if pointing to a row with no data */ - Bool nextRowidValid; /* True if the nextRowid field is valid */ - Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ - Btree *pBt; /* Separate file holding temporary table */ - int nData; /* Number of bytes in pData */ - char *pData; /* Data for a NEW or OLD pseudo-table */ - int iKey; /* Key for the NEW or OLD pseudo-table row */ -}; -typedef struct Cursor Cursor; - -/* -** A sorter builds a list of elements to be sorted. Each element of -** the list is an instance of the following structure. -*/ -typedef struct Sorter Sorter; -struct Sorter { - int nKey; /* Number of bytes in the key */ - char *zKey; /* The key by which we will sort */ - int nData; /* Number of bytes in the data */ - char *pData; /* The data associated with this key */ - Sorter *pNext; /* Next in the list */ -}; - -/* -** Number of buckets used for merge-sort. -*/ -#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 32 - -/* -** 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 */ - char z[NBFS]; /* Space for short strings */ -}; -typedef struct Stack Stack; - -/* -** Memory cells use the same structure as the stack except that space -** for an arbitrary string is added. -*/ -struct Mem { - Stack s; /* All values of the memory cell besides string */ - char *z; /* String value for this memory cell */ -}; -typedef struct Mem Mem; - -/* -** 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[] */ -#define STK_Static 0x0020 /* zStack[] points to a static string */ -#define STK_Ephem 0x0040 /* zStack[] points to an ephemeral string */ - -/* The following STK_ value appears only in AggElem.aMem.s.flag fields. -** It indicates that the corresponding AggElem.aMem.z points to a -** aggregate function context that needs to be finalized. -*/ -#define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */ - -/* -** The "context" argument for a installable function. A pointer to an -** instance of this structure is the first argument to the routines used -** implement the SQL functions. -** -** There is a typedef for this structure in sqlite.h. So all routines, -** even the public interface to SQLite, can use a pointer to this structure. -** But this file is the only place where the internal details of this -** structure are known. -** -** This structure is defined inside of vdbe.c because it uses substructures -** (Stack) which are only defined there. -*/ -struct sqlite_func { - FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ - Stack s; /* Small strings, ints, and double values go here */ - char *z; /* Space for holding dynamic string results */ - void *pAgg; /* Aggregate context */ - u8 isError; /* Set to true for an error */ - u8 isStep; /* Current in the step function */ - int cnt; /* Number of times that the step function has been called */ -}; - -/* -** An Agg structure describes an Aggregator. Each Agg consists of -** zero or more Aggregator elements (AggElem). Each AggElem contains -** a key and one or more values. The values are used in processing -** aggregate functions in a SELECT. The key is used to implement -** the GROUP BY clause of a select. -*/ -typedef struct Agg Agg; -typedef struct AggElem AggElem; -struct Agg { - int nMem; /* Number of values stored in each AggElem */ - AggElem *pCurrent; /* The AggElem currently in focus */ - HashElem *pSearch; /* The hash element for pCurrent */ - Hash hash; /* Hash table of all aggregate elements */ - FuncDef **apFunc; /* Information about aggregate functions */ -}; -struct AggElem { - char *zKey; /* The key to this AggElem */ - int nKey; /* Number of bytes in the key, including '\0' at end */ - Mem aMem[1]; /* The values for this AggElem */ -}; - -/* -** A Set structure is used for quick testing to see if a value -** is part of a small set. Sets are used to implement code like -** this: -** x.y IN ('hi','hoo','hum') -*/ -typedef struct Set Set; -struct Set { - Hash hash; /* A set is just a hash table */ - HashElem *prev; /* Previously accessed hash elemen */ -}; - -/* -** A Keylist is a bunch of keys into a table. The keylist can -** grow without bound. The keylist stores the ROWIDs of database -** records that need to be deleted or updated. -*/ -typedef struct Keylist Keylist; -struct Keylist { - int nKey; /* Number of slots in aKey[] */ - int nUsed; /* Next unwritten slot in aKey[] */ - int nRead; /* Next unread slot in aKey[] */ - Keylist *pNext; /* Next block of keys */ - int aKey[1]; /* One or more keys. Extra space allocated as needed */ -}; - -/* -** An instance of the virtual machine. This structure contains the complete -** state of the virtual machine. -** -** The "sqlite_vm" structure pointer that is returned by sqlite_compile() -** is really a pointer to an instance of this structure. -*/ -struct Vdbe { - sqlite *db; /* The whole database */ - Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ - FILE *trace; /* Write an execution trace here, if not NULL */ - int nOp; /* Number of instructions in the program */ - int nOpAlloc; /* Number of slots allocated for aOp[] */ - Op *aOp; /* Space to hold the virtual machine's program */ - int nLabel; /* Number of labels used */ - int nLabelAlloc; /* Number of slots allocated in aLabel[] */ - int *aLabel; /* Space to hold the labels */ - int tos; /* Index of top of 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 nCursor; /* Number of slots in aCsr[] */ - Cursor *aCsr; /* One element of this array for each open cursor */ - Sorter *pSort; /* A linked list of objects to be sorted */ - FILE *pFile; /* At most one open file handler */ - int nField; /* Number of file fields */ - char **azField; /* Data for each file field */ - int nVariable; /* Number of entries in azVariable[] */ - char **azVariable; /* Values for the OP_Variable opcode */ - char *zLine; /* A single line from the input file */ - int nLineAlloc; /* Number of spaces allocated for zLine */ - int magic; /* Magic number for sanity checking */ - int nMem; /* Number of memory locations currently allocated */ - Mem *aMem; /* The memory locations */ - Agg agg; /* Aggregate information */ - int nSet; /* Number of sets allocated */ - Set *aSet; /* An array of sets */ - int nCallback; /* Number of callbacks invoked so far */ - Keylist *pList; /* A list of ROWIDs */ - int keylistStackDepth; /* The size of the "keylist" stack */ - Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ - int pc; /* The program counter */ - int rc; /* Value to return */ - unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */ - int errorAction; /* Recovery action to do in case of an error */ - int undoTransOnError; /* If error, either ROLLBACK or COMMIT */ - int inTempTrans; /* True if temp database is transactioned */ - int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */ - int returnDepth; /* Next unused element in returnStack[] */ - int nResColumn; /* Number of columns in one row of the result set */ - char **azResColumn; /* Values for one row of result */ - int (*xCallback)(void*,int,char**,char**); /* Callback for SELECT results */ - void *pCbArg; /* First argument to xCallback() */ - int popStack; /* Pop the stack this much on entry to VdbeExec() */ - char *zErrMsg; /* Error message written here */ - u8 explain; /* True if EXPLAIN present on SQL command */ -}; - -/* -** The following are allowed values for Vdbe.magic -*/ -#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ -#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ -#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */ -#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ - -/* -** When debugging the code generator in a symbolic debugger, one can -** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed -** as they are added to the instruction stream. -*/ -#ifndef NDEBUG -int sqlite_vdbe_addop_trace = 0; -static void vdbePrintOp(FILE*, int, Op*); -#endif - -/* -** Create a new virtual database engine. -*/ -Vdbe *sqliteVdbeCreate(sqlite *db){ - Vdbe *p; - p = sqliteMalloc( sizeof(Vdbe) ); - if( p==0 ) return 0; - p->db = db; - if( db->pVdbe ){ - db->pVdbe->pPrev = p; - } - p->pNext = db->pVdbe; - p->pPrev = 0; - db->pVdbe = p; - p->magic = VDBE_MAGIC_INIT; - return p; -} - -/* -** Turn tracing on or off -*/ -void sqliteVdbeTrace(Vdbe *p, FILE *trace){ - p->trace = trace; -} - -/* -** Add a new instruction to the list of instructions current in the -** VDBE. Return the address of the new instruction. -** -** Parameters: -** -** p Pointer to the VDBE -** -** op The opcode for this instruction -** -** p1, p2 First two of the three possible operands. -** -** Use the sqliteVdbeResolveLabel() function to fix an address and -** the sqliteVdbeChangeP3() function to change the value of the P3 -** operand. -*/ -int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){ - int i; - - i = p->nOp; - p->nOp++; - assert( p->magic==VDBE_MAGIC_INIT ); - if( i>=p->nOpAlloc ){ - int oldSize = p->nOpAlloc; - Op *aNew; - p->nOpAlloc = p->nOpAlloc*2 + 100; - aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); - if( aNew==0 ){ - p->nOpAlloc = oldSize; - return 0; - } - p->aOp = aNew; - memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); - } - p->aOp[i].opcode = op; - p->aOp[i].p1 = p1; - if( p2<0 && (-1-p2)nLabel && p->aLabel[-1-p2]>=0 ){ - p2 = p->aLabel[-1-p2]; - } - p->aOp[i].p2 = p2; - p->aOp[i].p3 = 0; - p->aOp[i].p3type = P3_NOTUSED; -#ifndef NDEBUG - if( sqlite_vdbe_addop_trace ) vdbePrintOp(0, i, &p->aOp[i]); -#endif - return i; -} - -/* -** Create a new symbolic label for an instruction that has yet to be -** coded. The symbolic label is really just a negative number. The -** label can be used as the P2 value of an operation. Later, when -** the label is resolved to a specific address, the VDBE will scan -** through its operation list and change all values of P2 which match -** the label into the resolved address. -** -** The VDBE knows that a P2 value is a label because labels are -** always negative and P2 values are suppose to be non-negative. -** Hence, a negative P2 value is a label that has yet to be resolved. -*/ -int sqliteVdbeMakeLabel(Vdbe *p){ - int i; - i = p->nLabel++; - assert( p->magic==VDBE_MAGIC_INIT ); - if( i>=p->nLabelAlloc ){ - int *aNew; - p->nLabelAlloc = p->nLabelAlloc*2 + 10; - aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); - if( aNew==0 ){ - sqliteFree(p->aLabel); - } - p->aLabel = aNew; - } - if( p->aLabel==0 ){ - p->nLabel = 0; - p->nLabelAlloc = 0; - return 0; - } - p->aLabel[i] = -1; - return -1-i; -} - -/* -** Resolve label "x" to be the address of the next instruction to -** be inserted. The parameter "x" must have been obtained from -** a prior call to sqliteVdbeMakeLabel(). -*/ -void sqliteVdbeResolveLabel(Vdbe *p, int x){ - int j; - assert( p->magic==VDBE_MAGIC_INIT ); - if( x<0 && (-x)<=p->nLabel && p->aOp ){ - if( p->aLabel[-1-x]==p->nOp ) return; - assert( p->aLabel[-1-x]<0 ); - p->aLabel[-1-x] = p->nOp; - for(j=0; jnOp; j++){ - if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp; - } - } -} - -/* -** Return the address of the next instruction to be inserted. -*/ -int sqliteVdbeCurrentAddr(Vdbe *p){ - assert( p->magic==VDBE_MAGIC_INIT ); - return p->nOp; -} - -/* -** Add a whole list of operations to the operation stack. Return the -** address of the first operation added. -*/ -int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){ - int addr; - assert( p->magic==VDBE_MAGIC_INIT ); - if( p->nOp + nOp >= p->nOpAlloc ){ - int oldSize = p->nOpAlloc; - Op *aNew; - p->nOpAlloc = p->nOpAlloc*2 + nOp + 10; - aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); - if( aNew==0 ){ - p->nOpAlloc = oldSize; - return 0; - } - p->aOp = aNew; - memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); - } - addr = p->nOp; - if( nOp>0 ){ - int i; - for(i=0; iaOp[i+addr] = aOp[i]; - if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2); - p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED; -#ifndef NDEBUG - if( sqlite_vdbe_addop_trace ) vdbePrintOp(0, i+addr, &p->aOp[i+addr]); -#endif - } - p->nOp += nOp; - } - return addr; -} - -/* -** Change the value of the P1 operand for a specific instruction. -** This routine is useful when a large program is loaded from a -** static array using sqliteVdbeAddOpList but we want to make a -** few minor changes to the program. -*/ -void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){ - assert( p->magic==VDBE_MAGIC_INIT ); - if( p && addr>=0 && p->nOp>addr && p->aOp ){ - p->aOp[addr].p1 = val; - } -} - -/* -** Change the value of the P2 operand for a specific instruction. -** This routine is useful for setting a jump destination. -*/ -void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){ - assert( val>=0 ); - assert( p->magic==VDBE_MAGIC_INIT ); - if( p && addr>=0 && p->nOp>addr && p->aOp ){ - p->aOp[addr].p2 = val; - } -} - -/* -** Change the value of the P3 operand for a specific instruction. -** This routine is useful when a large program is loaded from a -** static array using sqliteVdbeAddOpList but we want to make a -** few minor changes to the program. -** -** If n>=0 then the P3 operand is dynamic, meaning that a copy of -** the string is made into memory obtained from sqliteMalloc(). -** A value of n==0 means copy bytes of zP3 up to and including the -** first null byte. If n>0 then copy n+1 bytes of zP3. -** -** If n==P3_STATIC it means that zP3 is a pointer to a constant static -** string and we can just copy the pointer. n==P3_POINTER means zP3 is -** a pointer to some object other than a string. -** -** If addr<0 then change P3 on the most recently inserted instruction. -*/ -void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ - Op *pOp; - assert( p->magic==VDBE_MAGIC_INIT ); - if( p==0 || p->aOp==0 ) return; - if( addr<0 || addr>=p->nOp ){ - addr = p->nOp - 1; - if( addr<0 ) return; - } - pOp = &p->aOp[addr]; - if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){ - sqliteFree(pOp->p3); - pOp->p3 = 0; - } - if( zP3==0 ){ - pOp->p3 = 0; - pOp->p3type = P3_NOTUSED; - }else if( n<0 ){ - pOp->p3 = (char*)zP3; - pOp->p3type = n; - }else{ - sqliteSetNString(&pOp->p3, zP3, n, 0); - pOp->p3type = P3_DYNAMIC; - } -} - -/* -** If the P3 operand to the specified instruction appears -** to be a quoted string token, then this procedure removes -** the quotes. -** -** The quoting operator can be either a grave ascent (ASCII 0x27) -** or a double quote character (ASCII 0x22). Two quotes in a row -** resolve to be a single actual quote character within the string. -*/ -void sqliteVdbeDequoteP3(Vdbe *p, int addr){ - Op *pOp; - assert( p->magic==VDBE_MAGIC_INIT ); - if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; - pOp = &p->aOp[addr]; - if( pOp->p3==0 || pOp->p3[0]==0 ) return; - if( pOp->p3type==P3_POINTER ) return; - if( pOp->p3type!=P3_DYNAMIC ){ - pOp->p3 = sqliteStrDup(pOp->p3); - pOp->p3type = P3_DYNAMIC; - } - sqliteDequote(pOp->p3); -} - -/* -** On the P3 argument of the given instruction, change all -** strings of whitespace characters into a single space and -** delete leading and trailing whitespace. -*/ -void sqliteVdbeCompressSpace(Vdbe *p, int addr){ - unsigned char *z; - int i, j; - Op *pOp; - assert( p->magic==VDBE_MAGIC_INIT ); - if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; - pOp = &p->aOp[addr]; - if( pOp->p3type==P3_POINTER ){ - return; - } - if( pOp->p3type!=P3_DYNAMIC ){ - pOp->p3 = sqliteStrDup(pOp->p3); - pOp->p3type = P3_DYNAMIC; - } - z = (unsigned char*)pOp->p3; - if( z==0 ) return; - i = j = 0; - while( isspace(z[i]) ){ i++; } - while( z[i] ){ - if( isspace(z[i]) ){ - z[j++] = ' '; - while( isspace(z[++i]) ){} - }else{ - z[j++] = z[i++]; - } - } - while( j>0 && isspace(z[j-1]) ){ j--; } - z[j] = 0; -} - -/* -** Search for the current program for the given opcode and P2 -** value. Return the address plus 1 if found and 0 if not found. -*/ -int sqliteVdbeFindOp(Vdbe *p, int op, int p2){ - int i; - assert( p->magic==VDBE_MAGIC_INIT ); - for(i=0; inOp; i++){ - if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1; - } - return 0; -} - -/* -** Return the opcode for a given address. -*/ -VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){ - assert( p->magic==VDBE_MAGIC_INIT ); - assert( addr>=0 && addrnOp ); - return &p->aOp[addr]; -} - -/* -** The following group or routines are employed by installable functions -** to return their results. -** -** The sqlite_set_result_string() routine can be used to return a string -** value or to return a NULL. To return a NULL, pass in NULL for zResult. -** A copy is made of the string before this routine returns so it is safe -** to pass in an ephemeral string. -** -** sqlite_set_result_error() works like sqlite_set_result_string() except -** that it signals a fatal error. The string argument, if any, is the -** error message. If the argument is NULL a generic substitute error message -** is used. -** -** The sqlite_set_result_int() and sqlite_set_result_double() set the return -** value of the user function to an integer or a double. -** -** These routines are defined here in vdbe.c because they depend on knowing -** the internals of the sqlite_func structure which is only defined in -** this source file. -*/ -char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){ - assert( !p->isStep ); - if( p->s.flags & STK_Dyn ){ - sqliteFree(p->z); - } - if( zResult==0 ){ - p->s.flags = STK_Null; - n = 0; - p->z = 0; - p->s.n = 0; - }else{ - if( n<0 ) n = strlen(zResult); - if( ns.z, zResult, n); - p->s.z[n] = 0; - p->s.flags = STK_Str; - p->z = p->s.z; - }else{ - p->z = sqliteMallocRaw( n+1 ); - if( p->z ){ - memcpy(p->z, zResult, n); - p->z[n] = 0; - } - p->s.flags = STK_Str | STK_Dyn; - } - p->s.n = n+1; - } - return p->z; -} -void sqlite_set_result_int(sqlite_func *p, int iResult){ - assert( !p->isStep ); - if( p->s.flags & STK_Dyn ){ - sqliteFree(p->z); - } - p->s.i = iResult; - p->s.flags = STK_Int; -} -void sqlite_set_result_double(sqlite_func *p, double rResult){ - assert( !p->isStep ); - if( p->s.flags & STK_Dyn ){ - sqliteFree(p->z); - } - p->s.r = rResult; - p->s.flags = STK_Real; -} -void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){ - assert( !p->isStep ); - sqlite_set_result_string(p, zMsg, n); - p->isError = 1; -} - -/* -** Extract the user data from a sqlite_func structure and return a -** pointer to it. -** -** This routine is defined here in vdbe.c because it depends on knowing -** the internals of the sqlite_func structure which is only defined in -** this source file. -*/ -void *sqlite_user_data(sqlite_func *p){ - assert( p && p->pFunc ); - return p->pFunc->pUserData; -} - -/* -** Allocate or return the aggregate context for a user function. A new -** context is allocated on the first call. Subsequent calls return the -** same context that was returned on prior calls. -** -** This routine is defined here in vdbe.c because it depends on knowing -** the internals of the sqlite_func structure which is only defined in -** this source file. -*/ -void *sqlite_aggregate_context(sqlite_func *p, int nByte){ - assert( p && p->pFunc && p->pFunc->xStep ); - if( p->pAgg==0 ){ - if( nByte<=NBFS ){ - p->pAgg = (void*)p->z; - }else{ - p->pAgg = sqliteMalloc( nByte ); - } - } - return p->pAgg; -} - -/* -** Return the number of times the Step function of a aggregate has been -** called. -** -** This routine is defined here in vdbe.c because it depends on knowing -** the internals of the sqlite_func structure which is only defined in -** this source file. -*/ -int sqlite_aggregate_count(sqlite_func *p){ - assert( p && p->pFunc && p->pFunc->xStep ); - return p->cnt; -} /* ** Advance the virtual machine to the next output row. @@ -831,50 +137,6 @@ int sqlite_step( return rc; } -/* -** Reset an Agg structure. Delete all its contents. -** -** For installable aggregate functions, if the step function has been -** called, make sure the finalizer function has also been called. The -** finalizer might need to free memory that was allocated as part of its -** private context. If the finalizer has not been called yet, call it -** now. -*/ -static void AggReset(Agg *pAgg){ - int i; - HashElem *p; - for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){ - AggElem *pElem = sqliteHashData(p); - assert( pAgg->apFunc!=0 ); - for(i=0; inMem; i++){ - Mem *pMem = &pElem->aMem[i]; - if( pAgg->apFunc[i] && (pMem->s.flags & STK_AggCtx)!=0 ){ - sqlite_func ctx; - ctx.pFunc = pAgg->apFunc[i]; - ctx.s.flags = STK_Null; - ctx.z = 0; - ctx.pAgg = pMem->z; - ctx.cnt = pMem->s.i; - ctx.isStep = 0; - ctx.isError = 0; - (*pAgg->apFunc[i]->xFinalize)(&ctx); - if( pMem->z!=0 && pMem->z!=pMem->s.z ){ - sqliteFree(pMem->z); - } - }else if( pMem->s.flags & STK_Dyn ){ - sqliteFree(pMem->z); - } - } - sqliteFree(pElem); - } - sqliteHashClear(&pAgg->hash); - sqliteFree(pAgg->apFunc); - pAgg->apFunc = 0; - pAgg->pCurrent = 0; - pAgg->pSearch = 0; - pAgg->nMem = 0; -} - /* ** Insert a new aggregate element and make it the element that ** has focus. @@ -1068,257 +330,6 @@ static void hardRealify(Vdbe *p, int i){ p->aStack[i].flags |= STK_Real; } -/* -** Pop the stack N times. Free any memory associated with the -** popped stack elements. -*/ -static void PopStack(Vdbe *p, int N){ - assert( N>=0 ); - if( p->zStack==0 ) return; - assert( p->aStack || sqlite_malloc_failed ); - if( p->aStack==0 ) return; - while( N-- > 0 ){ - if( p->aStack[p->tos].flags & STK_Dyn ){ - sqliteFree(p->zStack[p->tos]); - } - p->aStack[p->tos].flags = 0; - p->zStack[p->tos] = 0; - p->tos--; - } -} - -/* -** Here is a macro to handle the common case of popping the stack -** once. This macro only works from within the sqliteVdbeExec() -** function. -*/ -#define POPSTACK \ - assert(p->tos>=0); \ - if( aStack[p->tos].flags & STK_Dyn ) sqliteFree(zStack[p->tos]); \ - p->tos--; - -/* -** Delete a keylist -*/ -static void KeylistFree(Keylist *p){ - while( p ){ - Keylist *pNext = p->pNext; - sqliteFree(p); - p = pNext; - } -} - -/* -** Close a cursor and release all the resources that cursor happens -** to hold. -*/ -static void cleanupCursor(Cursor *pCx){ - if( pCx->pCursor ){ - sqliteBtreeCloseCursor(pCx->pCursor); - } - if( pCx->pBt ){ - sqliteBtreeClose(pCx->pBt); - } - sqliteFree(pCx->pData); - memset(pCx, 0, sizeof(Cursor)); -} - -/* -** Close all cursors -*/ -static void closeAllCursors(Vdbe *p){ - int i; - for(i=0; inCursor; i++){ - cleanupCursor(&p->aCsr[i]); - } - sqliteFree(p->aCsr); - p->aCsr = 0; - p->nCursor = 0; -} - -/* -** Remove any elements that remain on the sorter for the VDBE given. -*/ -static void SorterReset(Vdbe *p){ - while( p->pSort ){ - Sorter *pSorter = p->pSort; - p->pSort = pSorter->pNext; - sqliteFree(pSorter->zKey); - sqliteFree(pSorter->pData); - sqliteFree(pSorter); - } -} - -/* -** Delete the variables in p->azVariable[] -*/ -static void ClearVariableArray(Vdbe *p){ - sqliteFree(p->azVariable); - p->nVariable = 0; - p->azVariable = 0; -} - -/* -** Clean up the VM after execution. -** -** This routine will automatically close any cursors, lists, and/or -** sorters that were left open. It also deletes the values of -** variables in the azVariable[] array. -*/ -static void Cleanup(Vdbe *p){ - int i; - PopStack(p, p->tos+1); - closeAllCursors(p); - if( p->aMem ){ - for(i=0; inMem; i++){ - if( p->aMem[i].s.flags & STK_Dyn ){ - sqliteFree(p->aMem[i].z); - } - } - } - sqliteFree(p->aMem); - p->aMem = 0; - p->nMem = 0; - if( p->pList ){ - KeylistFree(p->pList); - p->pList = 0; - } - SorterReset(p); - 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; - AggReset(&p->agg); - if( p->aSet ){ - for(i=0; inSet; i++){ - sqliteHashClear(&p->aSet[i].hash); - } - } - sqliteFree(p->aSet); - p->aSet = 0; - p->nSet = 0; - if( p->keylistStack ){ - int ii; - for(ii = 0; ii < p->keylistStackDepth; ii++){ - KeylistFree(p->keylistStack[ii]); - } - sqliteFree(p->keylistStack); - p->keylistStackDepth = 0; - p->keylistStack = 0; - } - sqliteFree(p->zErrMsg); - p->zErrMsg = 0; - ClearVariableArray(p); -} - -/* -** Delete an entire VDBE. -*/ -void sqliteVdbeDelete(Vdbe *p){ - int i; - if( p==0 ) return; - Cleanup(p); - if( p->pPrev ){ - p->pPrev->pNext = p->pNext; - }else{ - assert( p->db->pVdbe==p ); - p->db->pVdbe = p->pNext; - } - if( p->pNext ){ - p->pNext->pPrev = p->pPrev; - } - p->pPrev = p->pNext = 0; - if( p->nOpAlloc==0 ){ - p->aOp = 0; - p->nOp = 0; - } - for(i=0; inOp; i++){ - if( p->aOp[i].p3type==P3_DYNAMIC ){ - sqliteFree(p->aOp[i].p3); - } - } - sqliteFree(p->aOp); - sqliteFree(p->aLabel); - sqliteFree(p->aStack); - p->magic = VDBE_MAGIC_DEAD; - sqliteFree(p); -} - -/* -** Give a listing of the program in the virtual machine. -** -** The interface is the same as sqliteVdbeExec(). But instead of -** running the code, it invokes the callback once for each instruction. -** This feature is used to implement "EXPLAIN". -*/ -int sqliteVdbeList( - Vdbe *p /* The VDBE */ -){ - sqlite *db = p->db; - int i; - static char *azColumnNames[] = { - "addr", "opcode", "p1", "p2", "p3", - "int", "text", "int", "int", "text", - 0 - }; - - assert( p->popStack==0 ); - assert( p->explain ); - p->azColName = azColumnNames; - p->azResColumn = p->zStack; - for(i=0; i<5; i++) p->zStack[i] = p->aStack[i].z; - p->rc = SQLITE_OK; - for(i=p->pc; p->rc==SQLITE_OK && inOp; i++){ - if( db->flags & SQLITE_Interrupt ){ - db->flags &= ~SQLITE_Interrupt; - if( db->magic!=SQLITE_MAGIC_BUSY ){ - p->rc = SQLITE_MISUSE; - }else{ - p->rc = SQLITE_INTERRUPT; - } - sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), 0); - break; - } - sprintf(p->zStack[0],"%d",i); - sprintf(p->zStack[2],"%d", p->aOp[i].p1); - sprintf(p->zStack[3],"%d", p->aOp[i].p2); - if( p->aOp[i].p3type==P3_POINTER ){ - sprintf(p->aStack[4].z, "ptr(%#x)", (int)p->aOp[i].p3); - p->zStack[4] = p->aStack[4].z; - }else{ - p->zStack[4] = p->aOp[i].p3; - } - p->zStack[1] = sqliteOpcodeNames[p->aOp[i].opcode]; - if( p->xCallback==0 ){ - p->pc = i+1; - p->azResColumn = p->zStack; - p->nResColumn = 5; - return SQLITE_ROW; - } - if( sqliteSafetyOff(db) ){ - p->rc = SQLITE_MISUSE; - break; - } - if( p->xCallback(p->pCbArg, 5, p->zStack, p->azColName) ){ - p->rc = SQLITE_ABORT; - } - if( sqliteSafetyOn(db) ){ - p->rc = SQLITE_MISUSE; - } - } - return p->rc==SQLITE_OK ? SQLITE_DONE : SQLITE_ERROR; -} - /* ** The parameters are pointers to the head of two sorted lists ** of Sorter structures. Merge these two lists together and return @@ -1424,26 +435,6 @@ static char *vdbe_fgets(char *zBuf, int nBuf, FILE *in){ return i>0 ? zBuf : 0; } -#if !defined(NDEBUG) || defined(VDBE_PROFILE) -/* -** Print a single opcode. This routine is used for debugging only. -*/ -static void vdbePrintOp(FILE *pOut, int pc, Op *pOp){ - char *zP3; - char zPtr[40]; - if( pOp->p3type==P3_POINTER ){ - sprintf(zPtr, "ptr(%#x)", (int)pOp->p3); - zP3 = zPtr; - }else{ - zP3 = pOp->p3; - } - if( pOut==0 ) pOut = stdout; - fprintf(pOut,"%4d %-12s %4d %4d %s\n", - pc, sqliteOpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : ""); - fflush(pOut); -} -#endif - /* ** Make sure there is space in the Vdbe structure to hold at least ** mxCursor cursors. If there is not currently enough space, then @@ -1493,77 +484,6 @@ __inline__ unsigned long long int hwtime(void){ if( db->flags & SQLITE_Interrupt ) goto abort_due_to_interrupt; -/* -** Prepare a virtual machine for execution. This involves things such -** as allocating stack space and initializing the program counter. -** After the VDBE has be prepped, it can be executed by one or more -** calls to sqliteVdbeExec(). -** -** The behavior of sqliteVdbeExec() is influenced by the parameters to -** this routine. If xCallback is NULL, then sqliteVdbeExec() will return -** with SQLITE_ROW whenever there is a row of the result set ready -** to be delivered. p->azResColumn will point to the row and -** p->nResColumn gives the number of columns in the row. If xCallback -** is not NULL, then the xCallback() routine is invoked to process each -** row in the result set. -*/ -void sqliteVdbeMakeReady( - Vdbe *p, /* The VDBE */ - sqlite_callback xCallback, /* Result callback */ - void *pCallbackArg, /* 1st argument to xCallback() */ - int isExplain /* True if the EXPLAIN keywords is present */ -){ - int n; - - assert( p!=0 ); - assert( p->aStack==0 ); - assert( p->magic==VDBE_MAGIC_INIT ); - - /* Add a HALT instruction to the very end of the program. - */ - if( p->nOp==0 || (p->aOp && p->aOp[p->nOp-1].opcode!=OP_Halt) ){ - sqliteVdbeAddOp(p, OP_Halt, 0, 0); - } - - /* No instruction ever pushes more than a single element onto the - ** stack. And the stack never grows on successive executions of the - ** same loop. So the total number of instructions is an upper bound - ** on the maximum stack depth required. - ** - ** Allocation all the stack space we will ever need. - */ - n = isExplain ? 10 : p->nOp; - p->aStack = sqliteMalloc( n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) ); - p->zStack = (char**)&p->aStack[n]; - p->azColName = (char**)&p->zStack[n]; - - sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0); - p->agg.pSearch = 0; -#ifdef MEMORY_DEBUG - if( sqliteOsFileExists("vdbe_trace") ){ - p->trace = stdout; - } -#endif - p->tos = -1; - p->pc = 0; - p->rc = SQLITE_OK; - p->uniqueCnt = 0; - p->returnDepth = 0; - p->errorAction = OE_Abort; - p->undoTransOnError = 0; - p->xCallback = xCallback; - p->pCbArg = pCallbackArg; - p->popStack = 0; - p->explain |= isExplain; - p->magic = VDBE_MAGIC_RUN; -#ifdef VDBE_PROFILE - for(i=0; inOp; i++){ - p->aOp[i].cnt = 0; - p->aOp[i].cycles = 0; - } -#endif -} - /* ** Execute as much of a VDBE program as we can then return. ** @@ -1617,7 +537,7 @@ int sqliteVdbeExec( assert( p->explain==0 ); if( sqlite_malloc_failed ) goto no_mem; if( p->popStack ){ - PopStack(p, p->popStack); + sqliteVdbePopStack(p, p->popStack); p->popStack = 0; } for(pc=p->pc; rc==SQLITE_OK; pc++){ @@ -1632,7 +552,7 @@ int sqliteVdbeExec( */ #ifndef NDEBUG if( p->trace ){ - vdbePrintOp(p->trace, pc, pOp); + sqliteVdbePrintOp(p->trace, pc, pOp); } #endif @@ -1814,7 +734,7 @@ case OP_Variable: { */ case OP_Pop: { assert( p->tos+1>=pOp->p1 ); - PopStack(p, pOp->p1); + sqliteVdbePopStack(p, pOp->p1); break; } @@ -1969,7 +889,7 @@ case OP_Callback: { } if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; p->nCallback++; - PopStack(p, pOp->p1); + sqliteVdbePopStack(p, pOp->p1); if( sqlite_malloc_failed ) goto no_mem; break; } @@ -2040,7 +960,7 @@ case OP_Concat: { } } if( nByte<0 ){ - if( pOp->p2==0 ) PopStack(p, nField); + if( pOp->p2==0 ) sqliteVdbePopStack(p, nField); p->tos++; aStack[p->tos].flags = STK_Null; zStack[p->tos] = 0; @@ -2060,7 +980,7 @@ case OP_Concat: { } } zNew[j] = 0; - if( pOp->p2==0 ) PopStack(p, nField); + if( pOp->p2==0 ) sqliteVdbePopStack(p, nField); p->tos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; @@ -2180,7 +1100,7 @@ case OP_Remainder: { break; divide_by_zero: - PopStack(p, 2); + sqliteVdbePopStack(p, 2); p->tos = nos; aStack[nos].flags = STK_Null; break; @@ -2214,7 +1134,7 @@ case OP_Function: { ctx.isError = 0; ctx.isStep = 0; (*ctx.pFunc->xFunc)(&ctx, n, (const char**)&zStack[p->tos-n+1]); - PopStack(p, n); + sqliteVdbePopStack(p, n); p->tos++; aStack[p->tos] = ctx.s; if( ctx.s.flags & STK_Dyn ){ @@ -2901,7 +1821,7 @@ case OP_IsNull: { break; } } - if( pOp->p1>0 ) PopStack(p, cnt); + if( pOp->p1>0 ) sqliteVdbePopStack(p, cnt); break; } @@ -3030,7 +1950,7 @@ case OP_MakeRecord: { j += aStack[i].n; } } - PopStack(p, nField); + sqliteVdbePopStack(p, nField); p->tos++; aStack[p->tos].n = nByte; if( nByte<=NBFS ){ @@ -3192,10 +2112,10 @@ case OP_MakeKey: { Integerify(p, p->tos-nField); iKey = intToKey(aStack[p->tos-nField].i); memcpy(&zNewKey[j], &iKey, sizeof(u32)); - PopStack(p, nField+1); + sqliteVdbePopStack(p, nField+1); if( pOp->p2 && containsNull ) pc = pOp->p2 - 1; }else{ - if( pOp->p2==0 ) PopStack(p, nField+addRowid); + if( pOp->p2==0 ) sqliteVdbePopStack(p, nField+addRowid); } p->tos++; aStack[p->tos].n = nByte; @@ -3505,7 +2425,7 @@ case OP_OpenWrite: { } VERIFY( if( i<0 ) goto bad_instruction; ) if( expandCursorArraySize(p, i) ) goto no_mem; - cleanupCursor(&p->aCsr[i]); + sqliteVdbeCleanupCursor(&p->aCsr[i]); memset(&p->aCsr[i], 0, sizeof(Cursor)); p->aCsr[i].nullRow = 1; if( pX==0 ) break; @@ -3563,7 +2483,7 @@ case OP_OpenTemp: { VERIFY( if( i<0 ) goto bad_instruction; ) if( expandCursorArraySize(p, i) ) goto no_mem; pCx = &p->aCsr[i]; - cleanupCursor(pCx); + sqliteVdbeCleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); pCx->nullRow = 1; rc = sqliteBtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt); @@ -3601,7 +2521,7 @@ case OP_OpenPseudo: { VERIFY( if( i<0 ) goto bad_instruction; ) if( expandCursorArraySize(p, i) ) goto no_mem; pCx = &p->aCsr[i]; - cleanupCursor(pCx); + sqliteVdbeCleanupCursor(pCx); memset(pCx, 0, sizeof(*pCx)); pCx->nullRow = 1; pCx->pseudoTable = 1; @@ -3616,7 +2536,7 @@ case OP_OpenPseudo: { case OP_Close: { int i = pOp->p1; if( i>=0 && inCursor ){ - cleanupCursor(&p->aCsr[i]); + sqliteVdbeCleanupCursor(&p->aCsr[i]); } break; } @@ -4824,7 +3744,7 @@ case OP_ListRead: { */ case OP_ListReset: { if( p->pList ){ - KeylistFree(p->pList); + sqliteVdbeKeylistFree(p->pList); p->pList = 0; } break; @@ -4854,7 +3774,7 @@ case OP_ListPush: { case OP_ListPop: { assert(p->keylistStackDepth > 0); p->keylistStackDepth--; - KeylistFree(p->pList); + sqliteVdbeKeylistFree(p->pList); p->pList = p->keylistStack[p->keylistStackDepth]; p->keylistStack[p->keylistStackDepth] = 0; if( p->keylistStackDepth == 0 ){ @@ -4932,7 +3852,7 @@ case OP_SortMakeRec: { z += aStack[i].n; } } - PopStack(p, nField); + sqliteVdbePopStack(p, nField); p->tos++; aStack[p->tos].n = nByte; zStack[p->tos] = (char*)azArg; @@ -4990,7 +3910,7 @@ case OP_SortMakeKey: { } zNewKey[j] = 0; assert( jtos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; @@ -5093,7 +4013,7 @@ case OP_SortCallback: { ** Remove any elements that remain on the sorter. */ case OP_SortReset: { - SorterReset(p); + sqliteVdbeSorterReset(p); break; } @@ -5373,7 +4293,7 @@ case OP_MemIncr: { ** Future aggregator elements will contain P2 values each. */ case OP_AggReset: { - AggReset(&p->agg); + sqliteVdbeAggReset(&p->agg); p->agg.nMem = pOp->p2; p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) ); if( p->agg.apFunc==0 ) goto no_mem; @@ -5432,7 +4352,7 @@ case OP_AggFunc: { (ctx.pFunc->xStep)(&ctx, n, (const char**)&zStack[p->tos-n]); pMem->z = ctx.pAgg; pMem->s.flags = STK_AggCtx; - PopStack(p, n+1); + sqliteVdbePopStack(p, n+1); if( ctx.isError ){ rc = SQLITE_ERROR; } @@ -5722,7 +4642,7 @@ default: { pOp->cnt++; #if 0 fprintf(stdout, "%10lld ", elapse); - vdbePrintOp(stdout, origPc, &p->aOp[origPc]); + sqliteVdbePrintOp(stdout, origPc, &p->aOp[origPc]); #endif } #endif @@ -5857,182 +4777,3 @@ bad_instruction: goto vdbe_halt; ) } - - -/* -** Clean up a VDBE after execution but do not delete the VDBE just yet. -** Write any error messages into *pzErrMsg. Return the result code. -** -** After this routine is run, the VDBE should be ready to be executed -** again. -*/ -int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){ - sqlite *db = p->db; - int i; - - if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ - sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); - return SQLITE_MISUSE; - } - if( p->zErrMsg ){ - if( pzErrMsg && *pzErrMsg==0 ){ - *pzErrMsg = p->zErrMsg; - }else{ - sqliteFree(p->zErrMsg); - } - p->zErrMsg = 0; - } - Cleanup(p); - if( p->rc!=SQLITE_OK ){ - switch( p->errorAction ){ - case OE_Abort: { - if( !p->undoTransOnError ){ - for(i=0; inDb; i++){ - if( db->aDb[i].pBt ){ - sqliteBtreeRollbackCkpt(db->aDb[i].pBt); - } - } - break; - } - /* Fall through to ROLLBACK */ - } - case OE_Rollback: { - sqliteRollbackAll(db); - db->flags &= ~SQLITE_InTrans; - db->onError = OE_Default; - break; - } - default: { - if( p->undoTransOnError ){ - sqliteRollbackAll(db); - db->flags &= ~SQLITE_InTrans; - db->onError = OE_Default; - } - break; - } - } - sqliteRollbackInternalChanges(db); - } - for(i=0; inDb; i++){ - if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){ - sqliteBtreeCommitCkpt(db->aDb[i].pBt); - db->aDb[i].inTrans = 1; - } - } - assert( p->tospc || sqlite_malloc_failed==1 ); -#ifdef VDBE_PROFILE - { - FILE *out = fopen("vdbe_profile.out", "a"); - if( out ){ - int i; - fprintf(out, "---- "); - for(i=0; inOp; i++){ - fprintf(out, "%02x", p->aOp[i].opcode); - } - fprintf(out, "\n"); - for(i=0; inOp; i++){ - fprintf(out, "%6d %10lld %8lld ", - p->aOp[i].cnt, - p->aOp[i].cycles, - p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 - ); - vdbePrintOp(out, i, &p->aOp[i]); - } - fclose(out); - } - } -#endif - p->magic = VDBE_MAGIC_INIT; - return p->rc; -} - -/* -** Clean up and delete a VDBE after execution. Return an integer which is -** the result code. Write any error message text into *pzErrMsg. -*/ -int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ - int rc; - sqlite *db; - - if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ - sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); - return SQLITE_MISUSE; - } - db = p->db; - rc = sqliteVdbeReset(p, pzErrMsg); - sqliteVdbeDelete(p); - if( db->want_to_close && db->pVdbe==0 ){ - sqlite_close(db); - } - return rc; -} - -/* -** Set the values of all variables. Variable $1 in the original SQL will -** be the string azValue[0]. $2 will have the value azValue[1]. And -** so forth. If a value is out of range (for example $3 when nValue==2) -** then its value will be NULL. -** -** This routine overrides any prior call. -*/ -int sqliteVdbeSetVariables(Vdbe *p, int nValue, const char **azValue){ - int i, n; - char *z; - if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 || p->nVariable!=0 ){ - return SQLITE_MISUSE; - } - ClearVariableArray(p); - if( nValue==0 ){ - p->nVariable = 0; - p->azVariable = 0; - } - for(i=n=0; iazVariable = sqliteMalloc( sizeof(p->azVariable[0])*nValue + n ); - if( p->azVariable==0 ){ - p->nVariable = 0; - return SQLITE_NOMEM; - } - z = (char*)&p->azVariable[nValue]; - for(i=0; iazVariable[i] = 0; - }else{ - p->azVariable[i] = z; - n = strlen(azValue[i]); - memcpy(z, azValue[i], n+1); - z += n+1; - } - } - p->nVariable = nValue; - return SQLITE_OK; -} - - -#if 0 -/* -** Create a new Vdbe in *pOut and populate it with the program from p. Then -** pass p to sqliteVdbeFinalize(). -*/ -int sqliteVdbeReset(Vdbe *p, char ** pErrMsg, Vdbe** pOut){ - if( pOut && p->rc != SQLITE_SCHEMA ){ - - /* Create a new VDBE and populate it with the program used by the old - ** VDBE. Don't copy the last instruction of the program, as this is an - ** OP_Halt coded by sqliteVdbeMakeReady(). - */ - *pOut = sqliteVdbeCreate( p->db ); - (*pOut)->aOp = p->aOp; - (*pOut)->nOp = p->nOp-1; - (*pOut)->nOpAlloc = p->nOpAlloc; - sqliteVdbeMakeReady( *pOut, p->xCallback, p->pCbArg, (int)p->explain ); - p->aOp = 0; - p->nOp = 0; - p->nOpAlloc = 0; - }else if( pOut ){ - *pOut = NULL; - } - return sqliteVdbeFinalize(p, pErrMsg); -} -#endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h new file mode 100644 index 0000000000..20aebdb4fa --- /dev/null +++ b/src/vdbeInt.h @@ -0,0 +1,297 @@ +/* +** 2003 September 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This is the header file for information that is private to the +** VDBE. This information used to all be at the top of the single +** source code file "vdbe.c". When that file became too big (over +** 6000 lines long) it was split up into several smaller files and +** this header information was factored out. +*/ + +/* +** The makefile scans this source file and creates the following +** array of string constants which are the names of all VDBE opcodes. +** This array is defined in a separate source code file named opcode.c +** which is automatically generated by the makefile. +*/ +extern char *sqliteOpcodeNames[]; + +/* +** SQL is translated into a sequence of instructions to be +** executed by a virtual machine. Each instruction is an instance +** of the following structure. +*/ +typedef struct VdbeOp Op; + +/* +** Boolean values +*/ +typedef unsigned char Bool; + +/* +** A cursor is a pointer into a single BTree within a database file. +** The cursor can seek to a BTree entry with a particular key, or +** loop over all entries of the Btree. You can also insert new BTree +** entries or retrieve the key or data from the entry that the cursor +** is currently pointing to. +** +** Every cursor that the virtual machine has open is represented by an +** instance of the following structure. +** +** If the Cursor.isTriggerRow flag is set it means that this cursor is +** really a single row that represents the NEW or OLD pseudo-table of +** a row trigger. The data for the row is stored in Cursor.pData and +** the rowid is in Cursor.iKey. +*/ +struct Cursor { + BtCursor *pCursor; /* The cursor structure of the backend */ + int lastRecno; /* Last recno from a Next or NextIdx operation */ + int nextRowid; /* Next rowid returned by OP_NewRowid */ + Bool recnoIsValid; /* True if lastRecno is valid */ + Bool keyAsData; /* The OP_Column command works on key instead of data */ + Bool atFirst; /* True if pointing to first entry */ + Bool useRandomRowid; /* Generate new record numbers semi-randomly */ + Bool nullRow; /* True if pointing to a row with no data */ + Bool nextRowidValid; /* True if the nextRowid field is valid */ + Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ + Btree *pBt; /* Separate file holding temporary table */ + int nData; /* Number of bytes in pData */ + char *pData; /* Data for a NEW or OLD pseudo-table */ + int iKey; /* Key for the NEW or OLD pseudo-table row */ +}; +typedef struct Cursor Cursor; + +/* +** A sorter builds a list of elements to be sorted. Each element of +** the list is an instance of the following structure. +*/ +typedef struct Sorter Sorter; +struct Sorter { + int nKey; /* Number of bytes in the key */ + char *zKey; /* The key by which we will sort */ + int nData; /* Number of bytes in the data */ + char *pData; /* The data associated with this key */ + Sorter *pNext; /* Next in the list */ +}; + +/* +** Number of buckets used for merge-sort. +*/ +#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 32 + +/* +** 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 */ + char z[NBFS]; /* Space for short strings */ +}; +typedef struct Stack Stack; + +/* +** Memory cells use the same structure as the stack except that space +** for an arbitrary string is added. +*/ +struct Mem { + Stack s; /* All values of the memory cell besides string */ + char *z; /* String value for this memory cell */ +}; +typedef struct Mem Mem; + +/* +** 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[] */ +#define STK_Static 0x0020 /* zStack[] points to a static string */ +#define STK_Ephem 0x0040 /* zStack[] points to an ephemeral string */ + +/* The following STK_ value appears only in AggElem.aMem.s.flag fields. +** It indicates that the corresponding AggElem.aMem.z points to a +** aggregate function context that needs to be finalized. +*/ +#define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */ + +/* +** The "context" argument for a installable function. A pointer to an +** instance of this structure is the first argument to the routines used +** implement the SQL functions. +** +** There is a typedef for this structure in sqlite.h. So all routines, +** even the public interface to SQLite, can use a pointer to this structure. +** But this file is the only place where the internal details of this +** structure are known. +** +** This structure is defined inside of vdbe.c because it uses substructures +** (Stack) which are only defined there. +*/ +struct sqlite_func { + FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ + Stack s; /* Small strings, ints, and double values go here */ + char *z; /* Space for holding dynamic string results */ + void *pAgg; /* Aggregate context */ + u8 isError; /* Set to true for an error */ + u8 isStep; /* Current in the step function */ + int cnt; /* Number of times that the step function has been called */ +}; + +/* +** An Agg structure describes an Aggregator. Each Agg consists of +** zero or more Aggregator elements (AggElem). Each AggElem contains +** a key and one or more values. The values are used in processing +** aggregate functions in a SELECT. The key is used to implement +** the GROUP BY clause of a select. +*/ +typedef struct Agg Agg; +typedef struct AggElem AggElem; +struct Agg { + int nMem; /* Number of values stored in each AggElem */ + AggElem *pCurrent; /* The AggElem currently in focus */ + HashElem *pSearch; /* The hash element for pCurrent */ + Hash hash; /* Hash table of all aggregate elements */ + FuncDef **apFunc; /* Information about aggregate functions */ +}; +struct AggElem { + char *zKey; /* The key to this AggElem */ + int nKey; /* Number of bytes in the key, including '\0' at end */ + Mem aMem[1]; /* The values for this AggElem */ +}; + +/* +** A Set structure is used for quick testing to see if a value +** is part of a small set. Sets are used to implement code like +** this: +** x.y IN ('hi','hoo','hum') +*/ +typedef struct Set Set; +struct Set { + Hash hash; /* A set is just a hash table */ + HashElem *prev; /* Previously accessed hash elemen */ +}; + +/* +** A Keylist is a bunch of keys into a table. The keylist can +** grow without bound. The keylist stores the ROWIDs of database +** records that need to be deleted or updated. +*/ +typedef struct Keylist Keylist; +struct Keylist { + int nKey; /* Number of slots in aKey[] */ + int nUsed; /* Next unwritten slot in aKey[] */ + int nRead; /* Next unread slot in aKey[] */ + Keylist *pNext; /* Next block of keys */ + int aKey[1]; /* One or more keys. Extra space allocated as needed */ +}; + +/* +** An instance of the virtual machine. This structure contains the complete +** state of the virtual machine. +** +** The "sqlite_vm" structure pointer that is returned by sqlite_compile() +** is really a pointer to an instance of this structure. +*/ +struct Vdbe { + sqlite *db; /* The whole database */ + Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ + FILE *trace; /* Write an execution trace here, if not NULL */ + int nOp; /* Number of instructions in the program */ + int nOpAlloc; /* Number of slots allocated for aOp[] */ + Op *aOp; /* Space to hold the virtual machine's program */ + int nLabel; /* Number of labels used */ + int nLabelAlloc; /* Number of slots allocated in aLabel[] */ + int *aLabel; /* Space to hold the labels */ + int tos; /* Index of top of 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 nCursor; /* Number of slots in aCsr[] */ + Cursor *aCsr; /* One element of this array for each open cursor */ + Sorter *pSort; /* A linked list of objects to be sorted */ + FILE *pFile; /* At most one open file handler */ + int nField; /* Number of file fields */ + char **azField; /* Data for each file field */ + int nVariable; /* Number of entries in azVariable[] */ + char **azVariable; /* Values for the OP_Variable opcode */ + char *zLine; /* A single line from the input file */ + int nLineAlloc; /* Number of spaces allocated for zLine */ + int magic; /* Magic number for sanity checking */ + int nMem; /* Number of memory locations currently allocated */ + Mem *aMem; /* The memory locations */ + Agg agg; /* Aggregate information */ + int nSet; /* Number of sets allocated */ + Set *aSet; /* An array of sets */ + int nCallback; /* Number of callbacks invoked so far */ + Keylist *pList; /* A list of ROWIDs */ + int keylistStackDepth; /* The size of the "keylist" stack */ + Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ + int pc; /* The program counter */ + int rc; /* Value to return */ + unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */ + int errorAction; /* Recovery action to do in case of an error */ + int undoTransOnError; /* If error, either ROLLBACK or COMMIT */ + int inTempTrans; /* True if temp database is transactioned */ + int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */ + int returnDepth; /* Next unused element in returnStack[] */ + int nResColumn; /* Number of columns in one row of the result set */ + char **azResColumn; /* Values for one row of result */ + int (*xCallback)(void*,int,char**,char**); /* Callback for SELECT results */ + void *pCbArg; /* First argument to xCallback() */ + int popStack; /* Pop the stack this much on entry to VdbeExec() */ + char *zErrMsg; /* Error message written here */ + u8 explain; /* True if EXPLAIN present on SQL command */ +}; + +/* +** The following are allowed values for Vdbe.magic +*/ +#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ +#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ +#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */ +#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ + +/* +** Here is a macro to handle the common case of popping the stack +** once. This macro only works from within the sqliteVdbeExec() +** function. +*/ +#define POPSTACK \ + assert(p->tos>=0); \ + if( aStack[p->tos].flags & STK_Dyn ) sqliteFree(zStack[p->tos]); \ + p->tos--; + +/* +** Function prototypes +*/ +void sqliteVdbeCleanupCursor(Cursor*); +void sqliteVdbeSorterReset(Vdbe*); +void sqliteVdbeAggReset(Agg*); +void sqliteVdbeKeylistFree(Keylist*); +void sqliteVdbePopStack(Vdbe*,int); +#if !defined(NDEBUG) || defined(VDBE_PROFILE) +void sqliteVdbePrintOp(FILE*, int, Op*); +#endif diff --git a/src/vdbeaux.c b/src/vdbeaux.c new file mode 100644 index 0000000000..9fedb8dd0b --- /dev/null +++ b/src/vdbeaux.c @@ -0,0 +1,996 @@ +/* +** 2003 September 6 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains code used for creating, destroying, and populating +** a VDBE (or an "sqlite_vm" as it is known to the outside world.) Prior +** to version 2.8.7, all this code was combined into the vdbe.c source file. +** But that file was getting too big so this subroutines were split out. +*/ +#include "sqliteInt.h" +#include "os.h" +#include +#include "vdbeInt.h" + + +/* +** When debugging the code generator in a symbolic debugger, one can +** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed +** as they are added to the instruction stream. +*/ +#ifndef NDEBUG +int sqlite_vdbe_addop_trace = 0; +#endif + + +/* +** Create a new virtual database engine. +*/ +Vdbe *sqliteVdbeCreate(sqlite *db){ + Vdbe *p; + p = sqliteMalloc( sizeof(Vdbe) ); + if( p==0 ) return 0; + p->db = db; + if( db->pVdbe ){ + db->pVdbe->pPrev = p; + } + p->pNext = db->pVdbe; + p->pPrev = 0; + db->pVdbe = p; + p->magic = VDBE_MAGIC_INIT; + return p; +} + +/* +** Turn tracing on or off +*/ +void sqliteVdbeTrace(Vdbe *p, FILE *trace){ + p->trace = trace; +} + +/* +** Add a new instruction to the list of instructions current in the +** VDBE. Return the address of the new instruction. +** +** Parameters: +** +** p Pointer to the VDBE +** +** op The opcode for this instruction +** +** p1, p2 First two of the three possible operands. +** +** Use the sqliteVdbeResolveLabel() function to fix an address and +** the sqliteVdbeChangeP3() function to change the value of the P3 +** operand. +*/ +int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){ + int i; + + i = p->nOp; + p->nOp++; + assert( p->magic==VDBE_MAGIC_INIT ); + if( i>=p->nOpAlloc ){ + int oldSize = p->nOpAlloc; + Op *aNew; + p->nOpAlloc = p->nOpAlloc*2 + 100; + aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); + if( aNew==0 ){ + p->nOpAlloc = oldSize; + return 0; + } + p->aOp = aNew; + memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); + } + p->aOp[i].opcode = op; + p->aOp[i].p1 = p1; + if( p2<0 && (-1-p2)nLabel && p->aLabel[-1-p2]>=0 ){ + p2 = p->aLabel[-1-p2]; + } + p->aOp[i].p2 = p2; + p->aOp[i].p3 = 0; + p->aOp[i].p3type = P3_NOTUSED; +#ifndef NDEBUG + if( sqlite_vdbe_addop_trace ) sqliteVdbePrintOp(0, i, &p->aOp[i]); +#endif + return i; +} + +/* +** Create a new symbolic label for an instruction that has yet to be +** coded. The symbolic label is really just a negative number. The +** label can be used as the P2 value of an operation. Later, when +** the label is resolved to a specific address, the VDBE will scan +** through its operation list and change all values of P2 which match +** the label into the resolved address. +** +** The VDBE knows that a P2 value is a label because labels are +** always negative and P2 values are suppose to be non-negative. +** Hence, a negative P2 value is a label that has yet to be resolved. +*/ +int sqliteVdbeMakeLabel(Vdbe *p){ + int i; + i = p->nLabel++; + assert( p->magic==VDBE_MAGIC_INIT ); + if( i>=p->nLabelAlloc ){ + int *aNew; + p->nLabelAlloc = p->nLabelAlloc*2 + 10; + aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); + if( aNew==0 ){ + sqliteFree(p->aLabel); + } + p->aLabel = aNew; + } + if( p->aLabel==0 ){ + p->nLabel = 0; + p->nLabelAlloc = 0; + return 0; + } + p->aLabel[i] = -1; + return -1-i; +} + +/* +** Resolve label "x" to be the address of the next instruction to +** be inserted. The parameter "x" must have been obtained from +** a prior call to sqliteVdbeMakeLabel(). +*/ +void sqliteVdbeResolveLabel(Vdbe *p, int x){ + int j; + assert( p->magic==VDBE_MAGIC_INIT ); + if( x<0 && (-x)<=p->nLabel && p->aOp ){ + if( p->aLabel[-1-x]==p->nOp ) return; + assert( p->aLabel[-1-x]<0 ); + p->aLabel[-1-x] = p->nOp; + for(j=0; jnOp; j++){ + if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp; + } + } +} + +/* +** Return the address of the next instruction to be inserted. +*/ +int sqliteVdbeCurrentAddr(Vdbe *p){ + assert( p->magic==VDBE_MAGIC_INIT ); + return p->nOp; +} + +/* +** Add a whole list of operations to the operation stack. Return the +** address of the first operation added. +*/ +int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){ + int addr; + assert( p->magic==VDBE_MAGIC_INIT ); + if( p->nOp + nOp >= p->nOpAlloc ){ + int oldSize = p->nOpAlloc; + Op *aNew; + p->nOpAlloc = p->nOpAlloc*2 + nOp + 10; + aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); + if( aNew==0 ){ + p->nOpAlloc = oldSize; + return 0; + } + p->aOp = aNew; + memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); + } + addr = p->nOp; + if( nOp>0 ){ + int i; + for(i=0; iaOp[i+addr] = aOp[i]; + if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2); + p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED; +#ifndef NDEBUG + if( sqlite_vdbe_addop_trace ){ + sqliteVdbePrintOp(0, i+addr, &p->aOp[i+addr]); + } +#endif + } + p->nOp += nOp; + } + return addr; +} + +/* +** Change the value of the P1 operand for a specific instruction. +** This routine is useful when a large program is loaded from a +** static array using sqliteVdbeAddOpList but we want to make a +** few minor changes to the program. +*/ +void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){ + assert( p->magic==VDBE_MAGIC_INIT ); + if( p && addr>=0 && p->nOp>addr && p->aOp ){ + p->aOp[addr].p1 = val; + } +} + +/* +** Change the value of the P2 operand for a specific instruction. +** This routine is useful for setting a jump destination. +*/ +void sqliteVdbeChangeP2(Vdbe *p, int addr, int val){ + assert( val>=0 ); + assert( p->magic==VDBE_MAGIC_INIT ); + if( p && addr>=0 && p->nOp>addr && p->aOp ){ + p->aOp[addr].p2 = val; + } +} + +/* +** Change the value of the P3 operand for a specific instruction. +** This routine is useful when a large program is loaded from a +** static array using sqliteVdbeAddOpList but we want to make a +** few minor changes to the program. +** +** If n>=0 then the P3 operand is dynamic, meaning that a copy of +** the string is made into memory obtained from sqliteMalloc(). +** A value of n==0 means copy bytes of zP3 up to and including the +** first null byte. If n>0 then copy n+1 bytes of zP3. +** +** If n==P3_STATIC it means that zP3 is a pointer to a constant static +** string and we can just copy the pointer. n==P3_POINTER means zP3 is +** a pointer to some object other than a string. +** +** If addr<0 then change P3 on the most recently inserted instruction. +*/ +void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ + Op *pOp; + assert( p->magic==VDBE_MAGIC_INIT ); + if( p==0 || p->aOp==0 ) return; + if( addr<0 || addr>=p->nOp ){ + addr = p->nOp - 1; + if( addr<0 ) return; + } + pOp = &p->aOp[addr]; + if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){ + sqliteFree(pOp->p3); + pOp->p3 = 0; + } + if( zP3==0 ){ + pOp->p3 = 0; + pOp->p3type = P3_NOTUSED; + }else if( n<0 ){ + pOp->p3 = (char*)zP3; + pOp->p3type = n; + }else{ + sqliteSetNString(&pOp->p3, zP3, n, 0); + pOp->p3type = P3_DYNAMIC; + } +} + +/* +** If the P3 operand to the specified instruction appears +** to be a quoted string token, then this procedure removes +** the quotes. +** +** The quoting operator can be either a grave ascent (ASCII 0x27) +** or a double quote character (ASCII 0x22). Two quotes in a row +** resolve to be a single actual quote character within the string. +*/ +void sqliteVdbeDequoteP3(Vdbe *p, int addr){ + Op *pOp; + assert( p->magic==VDBE_MAGIC_INIT ); + if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; + pOp = &p->aOp[addr]; + if( pOp->p3==0 || pOp->p3[0]==0 ) return; + if( pOp->p3type==P3_POINTER ) return; + if( pOp->p3type!=P3_DYNAMIC ){ + pOp->p3 = sqliteStrDup(pOp->p3); + pOp->p3type = P3_DYNAMIC; + } + sqliteDequote(pOp->p3); +} + +/* +** On the P3 argument of the given instruction, change all +** strings of whitespace characters into a single space and +** delete leading and trailing whitespace. +*/ +void sqliteVdbeCompressSpace(Vdbe *p, int addr){ + unsigned char *z; + int i, j; + Op *pOp; + assert( p->magic==VDBE_MAGIC_INIT ); + if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; + pOp = &p->aOp[addr]; + if( pOp->p3type==P3_POINTER ){ + return; + } + if( pOp->p3type!=P3_DYNAMIC ){ + pOp->p3 = sqliteStrDup(pOp->p3); + pOp->p3type = P3_DYNAMIC; + } + z = (unsigned char*)pOp->p3; + if( z==0 ) return; + i = j = 0; + while( isspace(z[i]) ){ i++; } + while( z[i] ){ + if( isspace(z[i]) ){ + z[j++] = ' '; + while( isspace(z[++i]) ){} + }else{ + z[j++] = z[i++]; + } + } + while( j>0 && isspace(z[j-1]) ){ j--; } + z[j] = 0; +} + +/* +** Search for the current program for the given opcode and P2 +** value. Return the address plus 1 if found and 0 if not found. +*/ +int sqliteVdbeFindOp(Vdbe *p, int op, int p2){ + int i; + assert( p->magic==VDBE_MAGIC_INIT ); + for(i=0; inOp; i++){ + if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1; + } + return 0; +} + +/* +** Return the opcode for a given address. +*/ +VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){ + assert( p->magic==VDBE_MAGIC_INIT ); + assert( addr>=0 && addrnOp ); + return &p->aOp[addr]; +} + +/* +** The following group or routines are employed by installable functions +** to return their results. +** +** The sqlite_set_result_string() routine can be used to return a string +** value or to return a NULL. To return a NULL, pass in NULL for zResult. +** A copy is made of the string before this routine returns so it is safe +** to pass in an ephemeral string. +** +** sqlite_set_result_error() works like sqlite_set_result_string() except +** that it signals a fatal error. The string argument, if any, is the +** error message. If the argument is NULL a generic substitute error message +** is used. +** +** The sqlite_set_result_int() and sqlite_set_result_double() set the return +** value of the user function to an integer or a double. +** +** These routines are defined here in vdbe.c because they depend on knowing +** the internals of the sqlite_func structure which is only defined in +** this source file. +*/ +char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){ + assert( !p->isStep ); + if( p->s.flags & STK_Dyn ){ + sqliteFree(p->z); + } + if( zResult==0 ){ + p->s.flags = STK_Null; + n = 0; + p->z = 0; + p->s.n = 0; + }else{ + if( n<0 ) n = strlen(zResult); + if( ns.z, zResult, n); + p->s.z[n] = 0; + p->s.flags = STK_Str; + p->z = p->s.z; + }else{ + p->z = sqliteMallocRaw( n+1 ); + if( p->z ){ + memcpy(p->z, zResult, n); + p->z[n] = 0; + } + p->s.flags = STK_Str | STK_Dyn; + } + p->s.n = n+1; + } + return p->z; +} +void sqlite_set_result_int(sqlite_func *p, int iResult){ + assert( !p->isStep ); + if( p->s.flags & STK_Dyn ){ + sqliteFree(p->z); + } + p->s.i = iResult; + p->s.flags = STK_Int; +} +void sqlite_set_result_double(sqlite_func *p, double rResult){ + assert( !p->isStep ); + if( p->s.flags & STK_Dyn ){ + sqliteFree(p->z); + } + p->s.r = rResult; + p->s.flags = STK_Real; +} +void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){ + assert( !p->isStep ); + sqlite_set_result_string(p, zMsg, n); + p->isError = 1; +} + +/* +** Extract the user data from a sqlite_func structure and return a +** pointer to it. +** +** This routine is defined here in vdbe.c because it depends on knowing +** the internals of the sqlite_func structure which is only defined in +** this source file. +*/ +void *sqlite_user_data(sqlite_func *p){ + assert( p && p->pFunc ); + return p->pFunc->pUserData; +} + +/* +** Allocate or return the aggregate context for a user function. A new +** context is allocated on the first call. Subsequent calls return the +** same context that was returned on prior calls. +** +** This routine is defined here in vdbe.c because it depends on knowing +** the internals of the sqlite_func structure which is only defined in +** this source file. +*/ +void *sqlite_aggregate_context(sqlite_func *p, int nByte){ + assert( p && p->pFunc && p->pFunc->xStep ); + if( p->pAgg==0 ){ + if( nByte<=NBFS ){ + p->pAgg = (void*)p->z; + }else{ + p->pAgg = sqliteMalloc( nByte ); + } + } + return p->pAgg; +} + +/* +** Return the number of times the Step function of a aggregate has been +** called. +** +** This routine is defined here in vdbe.c because it depends on knowing +** the internals of the sqlite_func structure which is only defined in +** this source file. +*/ +int sqlite_aggregate_count(sqlite_func *p){ + assert( p && p->pFunc && p->pFunc->xStep ); + return p->cnt; +} + +#if !defined(NDEBUG) || defined(VDBE_PROFILE) +/* +** Print a single opcode. This routine is used for debugging only. +*/ +void sqliteVdbePrintOp(FILE *pOut, int pc, Op *pOp){ + char *zP3; + char zPtr[40]; + if( pOp->p3type==P3_POINTER ){ + sprintf(zPtr, "ptr(%#x)", (int)pOp->p3); + zP3 = zPtr; + }else{ + zP3 = pOp->p3; + } + if( pOut==0 ) pOut = stdout; + fprintf(pOut,"%4d %-12s %4d %4d %s\n", + pc, sqliteOpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : ""); + fflush(pOut); +} +#endif + +/* +** Give a listing of the program in the virtual machine. +** +** The interface is the same as sqliteVdbeExec(). But instead of +** running the code, it invokes the callback once for each instruction. +** This feature is used to implement "EXPLAIN". +*/ +int sqliteVdbeList( + Vdbe *p /* The VDBE */ +){ + sqlite *db = p->db; + int i; + static char *azColumnNames[] = { + "addr", "opcode", "p1", "p2", "p3", + "int", "text", "int", "int", "text", + 0 + }; + + assert( p->popStack==0 ); + assert( p->explain ); + p->azColName = azColumnNames; + p->azResColumn = p->zStack; + for(i=0; i<5; i++) p->zStack[i] = p->aStack[i].z; + p->rc = SQLITE_OK; + for(i=p->pc; p->rc==SQLITE_OK && inOp; i++){ + if( db->flags & SQLITE_Interrupt ){ + db->flags &= ~SQLITE_Interrupt; + if( db->magic!=SQLITE_MAGIC_BUSY ){ + p->rc = SQLITE_MISUSE; + }else{ + p->rc = SQLITE_INTERRUPT; + } + sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), 0); + break; + } + sprintf(p->zStack[0],"%d",i); + sprintf(p->zStack[2],"%d", p->aOp[i].p1); + sprintf(p->zStack[3],"%d", p->aOp[i].p2); + if( p->aOp[i].p3type==P3_POINTER ){ + sprintf(p->aStack[4].z, "ptr(%#x)", (int)p->aOp[i].p3); + p->zStack[4] = p->aStack[4].z; + }else{ + p->zStack[4] = p->aOp[i].p3; + } + p->zStack[1] = sqliteOpcodeNames[p->aOp[i].opcode]; + if( p->xCallback==0 ){ + p->pc = i+1; + p->azResColumn = p->zStack; + p->nResColumn = 5; + return SQLITE_ROW; + } + if( sqliteSafetyOff(db) ){ + p->rc = SQLITE_MISUSE; + break; + } + if( p->xCallback(p->pCbArg, 5, p->zStack, p->azColName) ){ + p->rc = SQLITE_ABORT; + } + if( sqliteSafetyOn(db) ){ + p->rc = SQLITE_MISUSE; + } + } + return p->rc==SQLITE_OK ? SQLITE_DONE : SQLITE_ERROR; +} + +/* +** Prepare a virtual machine for execution. This involves things such +** as allocating stack space and initializing the program counter. +** After the VDBE has be prepped, it can be executed by one or more +** calls to sqliteVdbeExec(). +** +** The behavior of sqliteVdbeExec() is influenced by the parameters to +** this routine. If xCallback is NULL, then sqliteVdbeExec() will return +** with SQLITE_ROW whenever there is a row of the result set ready +** to be delivered. p->azResColumn will point to the row and +** p->nResColumn gives the number of columns in the row. If xCallback +** is not NULL, then the xCallback() routine is invoked to process each +** row in the result set. +*/ +void sqliteVdbeMakeReady( + Vdbe *p, /* The VDBE */ + sqlite_callback xCallback, /* Result callback */ + void *pCallbackArg, /* 1st argument to xCallback() */ + int isExplain /* True if the EXPLAIN keywords is present */ +){ + int n; + + assert( p!=0 ); + assert( p->aStack==0 ); + assert( p->magic==VDBE_MAGIC_INIT ); + + /* Add a HALT instruction to the very end of the program. + */ + if( p->nOp==0 || (p->aOp && p->aOp[p->nOp-1].opcode!=OP_Halt) ){ + sqliteVdbeAddOp(p, OP_Halt, 0, 0); + } + + /* No instruction ever pushes more than a single element onto the + ** stack. And the stack never grows on successive executions of the + ** same loop. So the total number of instructions is an upper bound + ** on the maximum stack depth required. + ** + ** Allocation all the stack space we will ever need. + */ + n = isExplain ? 10 : p->nOp; + p->aStack = sqliteMalloc( n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) ); + p->zStack = (char**)&p->aStack[n]; + p->azColName = (char**)&p->zStack[n]; + + sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0); + p->agg.pSearch = 0; +#ifdef MEMORY_DEBUG + if( sqliteOsFileExists("vdbe_trace") ){ + p->trace = stdout; + } +#endif + p->tos = -1; + p->pc = 0; + p->rc = SQLITE_OK; + p->uniqueCnt = 0; + p->returnDepth = 0; + p->errorAction = OE_Abort; + p->undoTransOnError = 0; + p->xCallback = xCallback; + p->pCbArg = pCallbackArg; + p->popStack = 0; + p->explain |= isExplain; + p->magic = VDBE_MAGIC_RUN; +#ifdef VDBE_PROFILE + for(i=0; inOp; i++){ + p->aOp[i].cnt = 0; + p->aOp[i].cycles = 0; + } +#endif +} + + +/* +** Remove any elements that remain on the sorter for the VDBE given. +*/ +void sqliteVdbeSorterReset(Vdbe *p){ + while( p->pSort ){ + Sorter *pSorter = p->pSort; + p->pSort = pSorter->pNext; + sqliteFree(pSorter->zKey); + sqliteFree(pSorter->pData); + sqliteFree(pSorter); + } +} + +/* +** Pop the stack N times. Free any memory associated with the +** popped stack elements. +*/ +void sqliteVdbePopStack(Vdbe *p, int N){ + assert( N>=0 ); + if( p->zStack==0 ) return; + assert( p->aStack || sqlite_malloc_failed ); + if( p->aStack==0 ) return; + while( N-- > 0 ){ + if( p->aStack[p->tos].flags & STK_Dyn ){ + sqliteFree(p->zStack[p->tos]); + } + p->aStack[p->tos].flags = 0; + p->zStack[p->tos] = 0; + p->tos--; + } +} + +/* +** Reset an Agg structure. Delete all its contents. +** +** For installable aggregate functions, if the step function has been +** called, make sure the finalizer function has also been called. The +** finalizer might need to free memory that was allocated as part of its +** private context. If the finalizer has not been called yet, call it +** now. +*/ +void sqliteVdbeAggReset(Agg *pAgg){ + int i; + HashElem *p; + for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){ + AggElem *pElem = sqliteHashData(p); + assert( pAgg->apFunc!=0 ); + for(i=0; inMem; i++){ + Mem *pMem = &pElem->aMem[i]; + if( pAgg->apFunc[i] && (pMem->s.flags & STK_AggCtx)!=0 ){ + sqlite_func ctx; + ctx.pFunc = pAgg->apFunc[i]; + ctx.s.flags = STK_Null; + ctx.z = 0; + ctx.pAgg = pMem->z; + ctx.cnt = pMem->s.i; + ctx.isStep = 0; + ctx.isError = 0; + (*pAgg->apFunc[i]->xFinalize)(&ctx); + if( pMem->z!=0 && pMem->z!=pMem->s.z ){ + sqliteFree(pMem->z); + } + }else if( pMem->s.flags & STK_Dyn ){ + sqliteFree(pMem->z); + } + } + sqliteFree(pElem); + } + sqliteHashClear(&pAgg->hash); + sqliteFree(pAgg->apFunc); + pAgg->apFunc = 0; + pAgg->pCurrent = 0; + pAgg->pSearch = 0; + pAgg->nMem = 0; +} + +/* +** Delete a keylist +*/ +void sqliteVdbeKeylistFree(Keylist *p){ + while( p ){ + Keylist *pNext = p->pNext; + sqliteFree(p); + p = pNext; + } +} + +/* +** Close a cursor and release all the resources that cursor happens +** to hold. +*/ +void sqliteVdbeCleanupCursor(Cursor *pCx){ + if( pCx->pCursor ){ + sqliteBtreeCloseCursor(pCx->pCursor); + } + if( pCx->pBt ){ + sqliteBtreeClose(pCx->pBt); + } + sqliteFree(pCx->pData); + memset(pCx, 0, sizeof(Cursor)); +} + +/* +** Close all cursors +*/ +static void closeAllCursors(Vdbe *p){ + int i; + for(i=0; inCursor; i++){ + sqliteVdbeCleanupCursor(&p->aCsr[i]); + } + sqliteFree(p->aCsr); + p->aCsr = 0; + p->nCursor = 0; +} + +/* +** Delete the variables in p->azVariable[] +*/ +static void ClearVariableArray(Vdbe *p){ + sqliteFree(p->azVariable); + p->nVariable = 0; + p->azVariable = 0; +} + +/* +** Clean up the VM after execution. +** +** This routine will automatically close any cursors, lists, and/or +** sorters that were left open. It also deletes the values of +** variables in the azVariable[] array. +*/ +static void Cleanup(Vdbe *p){ + int i; + sqliteVdbePopStack(p, p->tos+1); + closeAllCursors(p); + if( p->aMem ){ + for(i=0; inMem; i++){ + if( p->aMem[i].s.flags & STK_Dyn ){ + sqliteFree(p->aMem[i].z); + } + } + } + sqliteFree(p->aMem); + p->aMem = 0; + p->nMem = 0; + if( p->pList ){ + sqliteVdbeKeylistFree(p->pList); + p->pList = 0; + } + sqliteVdbeSorterReset(p); + 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; + sqliteVdbeAggReset(&p->agg); + if( p->aSet ){ + for(i=0; inSet; i++){ + sqliteHashClear(&p->aSet[i].hash); + } + } + sqliteFree(p->aSet); + p->aSet = 0; + p->nSet = 0; + if( p->keylistStack ){ + int ii; + for(ii = 0; ii < p->keylistStackDepth; ii++){ + sqliteVdbeKeylistFree(p->keylistStack[ii]); + } + sqliteFree(p->keylistStack); + p->keylistStackDepth = 0; + p->keylistStack = 0; + } + sqliteFree(p->zErrMsg); + p->zErrMsg = 0; + ClearVariableArray(p); +} + +/* +** Clean up a VDBE after execution but do not delete the VDBE just yet. +** Write any error messages into *pzErrMsg. Return the result code. +** +** After this routine is run, the VDBE should be ready to be executed +** again. +*/ +int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){ + sqlite *db = p->db; + int i; + + if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ + sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); + return SQLITE_MISUSE; + } + if( p->zErrMsg ){ + if( pzErrMsg && *pzErrMsg==0 ){ + *pzErrMsg = p->zErrMsg; + }else{ + sqliteFree(p->zErrMsg); + } + p->zErrMsg = 0; + } + Cleanup(p); + if( p->rc!=SQLITE_OK ){ + switch( p->errorAction ){ + case OE_Abort: { + if( !p->undoTransOnError ){ + for(i=0; inDb; i++){ + if( db->aDb[i].pBt ){ + sqliteBtreeRollbackCkpt(db->aDb[i].pBt); + } + } + break; + } + /* Fall through to ROLLBACK */ + } + case OE_Rollback: { + sqliteRollbackAll(db); + db->flags &= ~SQLITE_InTrans; + db->onError = OE_Default; + break; + } + default: { + if( p->undoTransOnError ){ + sqliteRollbackAll(db); + db->flags &= ~SQLITE_InTrans; + db->onError = OE_Default; + } + break; + } + } + sqliteRollbackInternalChanges(db); + } + for(i=0; inDb; i++){ + if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){ + sqliteBtreeCommitCkpt(db->aDb[i].pBt); + db->aDb[i].inTrans = 1; + } + } + assert( p->tospc || sqlite_malloc_failed==1 ); +#ifdef VDBE_PROFILE + { + FILE *out = fopen("vdbe_profile.out", "a"); + if( out ){ + int i; + fprintf(out, "---- "); + for(i=0; inOp; i++){ + fprintf(out, "%02x", p->aOp[i].opcode); + } + fprintf(out, "\n"); + for(i=0; inOp; i++){ + fprintf(out, "%6d %10lld %8lld ", + p->aOp[i].cnt, + p->aOp[i].cycles, + p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 + ); + sqliteVdbePrintOp(out, i, &p->aOp[i]); + } + fclose(out); + } + } +#endif + p->magic = VDBE_MAGIC_INIT; + return p->rc; +} + +/* +** Clean up and delete a VDBE after execution. Return an integer which is +** the result code. Write any error message text into *pzErrMsg. +*/ +int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ + int rc; + sqlite *db; + + if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ + sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); + return SQLITE_MISUSE; + } + db = p->db; + rc = sqliteVdbeReset(p, pzErrMsg); + sqliteVdbeDelete(p); + if( db->want_to_close && db->pVdbe==0 ){ + sqlite_close(db); + } + return rc; +} + +/* +** Set the values of all variables. Variable $1 in the original SQL will +** be the string azValue[0]. $2 will have the value azValue[1]. And +** so forth. If a value is out of range (for example $3 when nValue==2) +** then its value will be NULL. +** +** This routine overrides any prior call. +*/ +int sqliteVdbeSetVariables(Vdbe *p, int nValue, const char **azValue){ + int i, n; + char *z; + if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 || p->nVariable!=0 ){ + return SQLITE_MISUSE; + } + ClearVariableArray(p); + if( nValue==0 ){ + p->nVariable = 0; + p->azVariable = 0; + } + for(i=n=0; iazVariable = sqliteMalloc( sizeof(p->azVariable[0])*nValue + n ); + if( p->azVariable==0 ){ + p->nVariable = 0; + return SQLITE_NOMEM; + } + z = (char*)&p->azVariable[nValue]; + for(i=0; iazVariable[i] = 0; + }else{ + p->azVariable[i] = z; + n = strlen(azValue[i]); + memcpy(z, azValue[i], n+1); + z += n+1; + } + } + p->nVariable = nValue; + return SQLITE_OK; +} + + +/* +** Delete an entire VDBE. +*/ +void sqliteVdbeDelete(Vdbe *p){ + int i; + if( p==0 ) return; + Cleanup(p); + if( p->pPrev ){ + p->pPrev->pNext = p->pNext; + }else{ + assert( p->db->pVdbe==p ); + p->db->pVdbe = p->pNext; + } + if( p->pNext ){ + p->pNext->pPrev = p->pPrev; + } + p->pPrev = p->pNext = 0; + if( p->nOpAlloc==0 ){ + p->aOp = 0; + p->nOp = 0; + } + for(i=0; inOp; i++){ + if( p->aOp[i].p3type==P3_DYNAMIC ){ + sqliteFree(p->aOp[i].p3); + } + } + sqliteFree(p->aOp); + sqliteFree(p->aLabel); + sqliteFree(p->aStack); + p->magic = VDBE_MAGIC_DEAD; + sqliteFree(p); +}