diff --git a/manifest b/manifest index 55c6497347..b041b4fb83 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\slogo\sfrom\sRasmus\sSchultz.\s(CVS\s1092) -D 2003-09-02T15:26:33 +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 F Makefile.in f7e916ae863393827fa6a4cb292e3398096edcf1 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -30,39 +30,39 @@ F src/build.c 7cdc95266496f53673a66202477b137d514898cf F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73 F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc F src/encode.c 25ea901a9cefb3d93774afa4a06b57cb58acf544 -F src/expr.c 03c321ac66c1e998c2e0faf22184b5a808b559ca -F src/func.c be22d719450ffa4c2e04adec96d9116a4c0cdb62 +F src/expr.c 0c10a35c15756e90940d946cdec1e5c7d860ddc9 +F src/func.c 377ea94127351de27892a62a63f931e0fbaa33d4 F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c dc200ae04a36bd36e575272a069e20c528b7fbdf -F src/main.c 2500392bad5629b6d70b06ac5a076958acb49b92 +F src/main.c e472b0c86b811a76b6a17760c945acfabd8ba935 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c 97df440bc71f65e22df5d3d920ce39551c0a5f5a F src/os.h 729395fefcca4b81ae056aa9ff67b72bb40dd9e0 -F src/pager.c 77e1a7de50197e5fc87353c36006a304756b0747 +F src/pager.c 62702dff51d50694d039bc210f31990d1fbba2dd F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31 -F src/parse.y 16aed0e3ed05445fa7f6a4209cc054208c7083c0 +F src/parse.y 5cd707f0e5444b1dd168e414dd2c055fb158db5c F src/pragma.c cee60f17679210e8acd30d5bdee855716d0c898c F src/printf.c 12e45d482ac8abcc6f786fc99e5bed7dd9a51af0 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/select.c 2fa83d6c972d3e3f379faee32e3621411490dedb F src/shell.c c2ba26c850874964f5ec1ebf6c43406f28e44c4a F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e -F src/sqlite.h.in dafa83571810b6932f089b589c783355ef7a54b5 +F src/sqlite.h.in 72c07cf3b70c42a0e829270527f7b40a55d4a2d6 F src/sqliteInt.h e68eb1eeba806905acc9ed491f4c5b96587020df F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95 F src/tclsqlite.c ec9e5b796bf9ec1483927e986828a205d4a7422a -F src/test1.c b12b585bfb4763df3262975ed8d3f4f274b5eaed +F src/test1.c 751e11106c637d8ee64ecf95597b0133c544ab9f F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e -F src/tokenize.c 2ba93fe10d5f57f0cc20b07417c3244a30c324b3 +F src/tokenize.c ea4e89b37db050fb99ae4c916bd7671375845aaf F src/trigger.c 474581eaab388233df01bb019e558af2965decbf F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397 F src/util.c f16efa2d60bfd4e31ae06b07ed149557e828d294 F src/vacuum.c e4724eade07e4cf8897060a8cf632dbd92408eeb -F src/vdbe.c 306f59011785428e2d19578ca1fcd7a1304f57f7 -F src/vdbe.h d853ed6cc4727fa9e8ace6187c55afcf817041dd +F src/vdbe.c b6a2b0a8eeca95cc29a9e07fb7d2cc3c1eaec468 +F src/vdbe.h 3c51cb382316dbf3860e4ece72e658b4bf014501 F src/where.c 83b2a2d26d5c3bea33457a83e541bb1dcf7b1248 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test c26848402e7ac829e043e1fa5e0eb87032e5d81d @@ -170,7 +170,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P 522c2efeb5bdccadf3306234d458425b94cdbbe3 -R 5b61a815079f1971babe212bb4f8b793 +P aaa84c6202f6e16828bcd6aff2e424f3dba1f82b +R 0bb0019009c0a448d322679ad1dd5f73 U drh -Z f92c2044c3f4c2f842d2611b3febcf40 +Z 42cb329fb1ec590b60ca4f6b47463c49 diff --git a/manifest.uuid b/manifest.uuid index 0d4d8c2e03..b0c5bbb28c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aaa84c6202f6e16828bcd6aff2e424f3dba1f82b \ No newline at end of file +912f47c72d3597c6d5acff765d94922bd660339a \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 804e751b79..46bd04d471 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.98 2003/07/30 12:34:12 drh Exp $ +** $Id: expr.c,v 1.99 2003/09/06 01:10:47 drh Exp $ */ #include "sqliteInt.h" #include @@ -310,6 +310,7 @@ int sqliteExprIsConstant(Expr *p){ case TK_STRING: case TK_INTEGER: case TK_FLOAT: + case TK_VARIABLE: return 1; default: { if( p->pLeft && !sqliteExprIsConstant(p->pLeft) ) return 0; @@ -914,6 +915,7 @@ int sqliteExprType(Expr *p){ case TK_STRING: case TK_NULL: case TK_CONCAT: + case TK_VARIABLE: return SQLITE_SO_TEXT; case TK_LT: @@ -1043,6 +1045,10 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ sqliteVdbeAddOp(v, OP_String, 0, 0); break; } + case TK_VARIABLE: { + sqliteVdbeAddOp(v, OP_Variable, atoi(&pExpr->token.z[1]), 0); + break; + } case TK_LT: case TK_LE: case TK_GT: diff --git a/src/func.c b/src/func.c index c7d2eb51e6..2e3c20728e 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.30 2003/08/26 11:41:27 drh Exp $ +** $Id: func.c,v 1.31 2003/09/06 01:10:47 drh Exp $ */ #include #include @@ -542,6 +542,9 @@ static void minMaxFinalize(sqlite_func *context){ /**************************************************************************** ** Time and date functions. ** +** 1970-01-01 00:00:00 is JD 2440587.5. +** 2000-01-01 00:00:00 is JD 2451544.5 +** ** SQLite processes all times and dates as Julian Day numbers. The ** dates and times are stored as the number of days since noon ** in Greenwich on November 24, 4714 B.C. according to the Gregorian diff --git a/src/main.c b/src/main.c index 27c2ec92b2..29a4d2ca0d 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.140 2003/07/27 17:26:23 drh Exp $ +** $Id: main.c,v 1.141 2003/09/06 01:10:47 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -695,6 +695,32 @@ int sqlite_compile( return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg); } +/* +** If the SQL that was handed to sqlite_compile contains variables of +** the form $1, $2, $3, etc. then this routine assigns values to those +** variables. azValue[0] is assigned to $1. azValue[1] is assigned +** to $2. And so forth. The value of variable $0 will always be NULL. +** The values of any variable $N where N>nValue will be NULL. If any +** azValue[] is a NULL pointer, then the corresponding variable will be +** NULL. +** +** This routine can only be called immediately after sqlite_compile() +** or sqlite_reset() and before any calls to sqlite_step(). +** +** This routine makes copies of all strings in azValue[] so the values +** passed in can be changed or deleted immediately after this call. The +** copies are deallocated when sqlite_finalize() or sqlite_reset() is +** invoked. +*/ +int sqlite_instantiate( + sqlite_vm *pVm, + int nValue, + const char **azValue +){ + return sqliteVdbeSetVariables((Vdbe*)pVm, nValue, azValue); +} + + /* ** The following routine destroys a virtual machine that is created by ** the sqlite_compile() routine. @@ -716,16 +742,18 @@ int sqlite_finalize( } /* -** Destroy a virtual machine in the same manner as sqlite_finalize(). If -** possible, leave *ppVm pointing at a new virtual machine which may be -** used to re-execute the query. +** Terminate the current execution of a virtual machine then +** reset the virtual machine back to its starting state so that it +** can be reused. Any error message resulting from the prior execution +** is written into *pzErrMsg. A success code from the prior execution +** is returned. */ int sqlite_reset( sqlite_vm *pVm, /* The virtual machine to be destroyed */ - char **pzErrMsg, /* OUT: Write error messages here */ - sqlite_vm **ppVm /* OUT: The new virtual machine */ + char **pzErrMsg /* OUT: Write error messages here */ ){ - int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg, (Vdbe **)ppVm); + int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg); + sqliteVdbeMakeReady((Vdbe*)pVm, 0, 0, 0); sqliteStrRealloc(pzErrMsg); return rc; } diff --git a/src/pager.c b/src/pager.c index 5a58e6d686..c3fff42ac2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.89 2003/08/26 11:41:27 drh Exp $ +** @(#) $Id: pager.c,v 1.90 2003/09/06 01:10:47 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -426,6 +426,10 @@ static void pager_reset(Pager *pPager){ ** a write lock on the database. This routine releases the database ** write lock and acquires a read lock in its place. The journal file ** is deleted and closed. +** +** TODO: Consider keeping the journal file open for temporary databases. +** This might give a performance improvement on windows where opening +** a file is an expensive operation. */ static int pager_unwritelock(Pager *pPager){ int rc; diff --git a/src/parse.y b/src/parse.y index 4efb90ed76..5ea4f410f3 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.99 2003/07/16 02:19:38 drh Exp $ +** @(#) $Id: parse.y,v 1.100 2003/09/06 01:10:48 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -541,6 +541,7 @@ expr(A) ::= expr(B) ORACLE_OUTER_JOIN. expr(A) ::= INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);} expr(A) ::= FLOAT(X). {A = sqliteExpr(TK_FLOAT, 0, 0, &X);} expr(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);} +expr(A) ::= VARIABLE(X). {A = sqliteExpr(TK_VARIABLE, 0, 0, &X);} expr(A) ::= ID(X) LP exprlist(Y) RP(E). { A = sqliteExprFunction(Y, &X); sqliteExprSpan(A,&X,&E); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2980f817e7..bcf8b38a2b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.50 2003/07/22 09:24:44 danielk1977 Exp $ +** @(#) $Id: sqlite.h.in,v 1.51 2003/09/06 01:10:48 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -695,9 +695,31 @@ int sqlite_finalize(sqlite_vm*, char **pzErrMsg); ** ** If sqlite_reset() returns SQLITE_SCHEMA, then *ppVm is set to NULL. ** +*/ +int sqlite_reset(sqlite_vm *, char **pzErrMsg); + +/* +** If the SQL that was handed to sqlite_compile contains variables of +** the form $1, $2, $3, etc. then this routine assigns values to those +** variables. azValue[0] is assigned to $1. azValue[1] is assigned +** to $2. And so forth. The value of variable $0 will always be NULL. +** The values of any variable $N where N>nValue will be NULL. If any +** azValue[] is a NULL pointer, then the corresponding variable will be +** NULL. +** +** This routine can only be called immediately after sqlite_compile() +** or sqlite_reset() and before any calls to sqlite_step(). +** +** This routine makes copies of all strings in azValue[] so the values +** passed in can be changed or deleted immediately after this call. The +** copies are deallocated when sqlite_finalize() or sqlite_reset() is +** invoked. +** ******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** */ -int sqlite_reset(sqlite_vm *, char **pzErrMsg, sqlite_vm **ppVm); +int sqlite_instantiate(sqlite_vm*, int, const char**); + + #ifdef __cplusplus } /* End of the 'extern "C"' block */ diff --git a/src/test1.c b/src/test1.c index 3ec97d7e7f..d768d3440c 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.26 2003/07/09 00:28:15 drh Exp $ +** $Id: test1.c,v 1.27 2003/09/06 01:10:48 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -774,6 +774,66 @@ static int test_finalize( return TCL_OK; } +/* +** Usage: sqlite_reset VM +** +** Reset a virtual machine and prepare it to be run again. +*/ +static int test_reset( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + sqlite_vm *vm; + int rc; + char *zErrMsg = 0; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " VM\"", 0); + return TCL_ERROR; + } + if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; + rc = sqlite_reset(vm, &zErrMsg); + if( rc ){ + char zBuf[50]; + sprintf(zBuf, "(%d) ", rc); + Tcl_AppendResult(interp, zBuf, zErrMsg, 0); + sqlite_freemem(zErrMsg); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: sqlite_instantiate VM ARGS... +** +** Set the values of variables (ex: $1, $2, etc) in the original SQL string. +*/ +static int test_instantiate( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + sqlite_vm *vm; + int rc; + if( argc<2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " VM ARGS...\"", 0); + return TCL_ERROR; + } + if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; + rc = sqlite_instantiate(vm, argc-2, &argv[2]); + if( rc ){ + char zBuf[50]; + sprintf(zBuf, "(%d) ", rc); + Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + /* ** Usage: breakpoint ** @@ -827,6 +887,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite_compile", (Tcl_CmdProc*)test_compile }, { "sqlite_step", (Tcl_CmdProc*)test_step }, { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, + { "sqlite_instantiate", (Tcl_CmdProc*)test_instantiate }, + { "sqlite_reset", (Tcl_CmdProc*)test_reset }, { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, }; int i; diff --git a/src/tokenize.c b/src/tokenize.c index 66ecae06c2..7a187186e6 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.60 2003/05/04 18:30:59 drh Exp $ +** $Id: tokenize.c,v 1.61 2003/09/06 01:10:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -380,6 +380,12 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){ *tokenType = TK_ID; return i; } + case '$': { + if( !isdigit(z[1]) ) break; + for(i=1; z[i] && isdigit(z[i]); i++){} + *tokenType = TK_VARIABLE; + return i; + } default: { if( !isIdChar[*z] ){ break; diff --git a/src/vdbe.c b/src/vdbe.c index 1df38bf200..de33d162d7 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -36,7 +36,7 @@ ** 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.237 2003/08/26 11:35:00 drh Exp $ +** $Id: vdbe.c,v 1.238 2003/09/06 01:10:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -270,9 +270,11 @@ struct Vdbe { 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 magic; /* Magic number for sanity checking */ 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 */ @@ -1147,11 +1149,21 @@ static void SorterReset(Vdbe *p){ } } +/* +** 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. +** sorters that were left open. It also deletes the values of +** variables in the azVariable[] array. */ static void Cleanup(Vdbe *p){ int i; @@ -1206,7 +1218,7 @@ static void Cleanup(Vdbe *p){ } sqliteFree(p->zErrMsg); p->zErrMsg = 0; - p->magic = VDBE_MAGIC_DEAD; + ClearVariableArray(p); } /* @@ -1238,6 +1250,7 @@ void sqliteVdbeDelete(Vdbe *p){ sqliteFree(p->aOp); sqliteFree(p->aLabel); sqliteFree(p->aStack); + p->magic = VDBE_MAGIC_DEAD; sqliteFree(p); } @@ -1508,7 +1521,9 @@ void sqliteVdbeMakeReady( /* Add a HALT instruction to the very end of the program. */ - sqliteVdbeAddOp(p, OP_Halt, 0, 0); + 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 @@ -1539,7 +1554,7 @@ void sqliteVdbeMakeReady( p->xCallback = xCallback; p->pCbArg = pCallbackArg; p->popStack = 0; - p->explain = isExplain; + p->explain |= isExplain; p->magic = VDBE_MAGIC_RUN; #ifdef VDBE_PROFILE for(i=0; inOp; i++){ @@ -1772,6 +1787,27 @@ case OP_String: { break; } +/* Opcode: Variable P1 * * +** +** Push the value of variable P1 onto the stack. A variable is +** an unknown in the original SQL string as handed to sqlite_compile(). +** The first variable is $1, the second is $2, and so forth. The +** value of the variables is determined by sqlite_instantiate(). +*/ +case OP_Variable: { + int i = ++p->tos; + if( pOp->p1>0 && pOp->p1<=p->nVariable && p->azVariable[pOp->p1-1]!=0 ){ + zStack[i] = p->azVariable[pOp->p1-1]; + aStack[i].n = strlen(zStack[i]) + 1; + aStack[i].flags = STK_Str | STK_Static; + }else{ + zStack[i] = 0; + aStack[i].n = 0; + aStack[i].flags = STK_Null; + } + break; +} + /* Opcode: Pop P1 * * ** ** P1 elements are popped off of the top of stack and discarded. @@ -3025,9 +3061,17 @@ case OP_MakeRecord: { ** back in its place. ** ** P3 is a string that is P1 characters long. Each character is either -** an 'n' or a 't' to indicates if the argument should be numeric or -** text. The first character corresponds to the lowest element on the -** stack. If P3 is NULL then all arguments are assumed to be numeric. +** an 'n' or a 't' to indicates if the argument should be intepreted as +** numeric or text type. The first character of P3 corresponds to the +** lowest element on the stack. If P3 is NULL then all arguments are +** assumed to be of the numeric type. +** +** The type makes a difference in that text-type fields may not be +** introduced by 'b' (as described in the next paragraph). The +** first character of a text-type field must be either 'a' (if it is NULL) +** or 'c'. Numeric fields will be introduced by 'b' if their content +** looks like a well-formed number. Otherwise the 'a' or 'c' will be +** used. ** ** The key is a concatenation of fields. Each field is terminated by ** a single 0x00 character. A NULL field is introduced by an 'a' and @@ -3039,7 +3083,7 @@ case OP_MakeRecord: { ** sqliteRealToSortable() function. A text field is introduced by a ** 'c' character and is followed by the exact text of the field. The ** use of an 'a', 'b', or 'c' character at the beginning of each field -** guarantees that NULL sort before numbers and that numbers sort +** guarantees that NULLs sort before numbers and that numbers sort ** before text. 0x00 characters do not occur except as separators ** between fields. ** @@ -5816,12 +5860,15 @@ bad_instruction: /* -** Clean up the VDBE after execution. Return an integer which is the -** result code. +** 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 sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ +int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){ sqlite *db = p->db; - int i, rc; + int i; if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); @@ -5895,7 +5942,24 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ } } #endif - rc = p->rc; + 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); @@ -5903,12 +5967,55 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ 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) -{ +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 @@ -5928,3 +6035,4 @@ int sqliteVdbeReset(Vdbe *p, char ** pErrMsg, Vdbe** pOut) } return sqliteVdbeFinalize(p, pErrMsg); } +#endif diff --git a/src/vdbe.h b/src/vdbe.h index 9d77ac5695..494313dcb4 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.66 2003/07/22 09:24:44 danielk1977 Exp $ +** $Id: vdbe.h,v 1.67 2003/09/06 01:10:49 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -92,6 +92,7 @@ void sqliteVdbeResolveLabel(Vdbe*, int); int sqliteVdbeCurrentAddr(Vdbe*); void sqliteVdbeTrace(Vdbe*,FILE*); void sqliteVdbeCompressSpace(Vdbe*,int); -int sqliteVdbeReset(Vdbe*,char **,Vdbe**); +int sqliteVdbeReset(Vdbe*,char **); +int sqliteVdbeSetVariables(Vdbe*,int,const char**); #endif