diff --git a/Makefile.in b/Makefile.in index 7585de32ab..9c8f475185 100644 --- a/Makefile.in +++ b/Makefile.in @@ -82,7 +82,7 @@ LIBOBJ = attach.lo auth.lo btree.lo build.lo copy.lo \ delete.lo expr.lo func.lo hash.lo insert.lo \ main.lo opcodes.lo os.lo pager.lo parse.lo pragma.lo \ printf.lo random.lo select.lo table.lo tokenize.lo \ - update.lo util.lo vacuum.lo vdbe.lo \ + update.lo util.lo vacuum.lo vdbe.lo vdbeaux.lo \ where.lo trigger.lo # Only build the in-core DB if it is required. @@ -126,6 +126,7 @@ SRC = \ $(TOP)/src/util.c \ $(TOP)/src/vacuum.c \ $(TOP)/src/vdbe.c \ + $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbe.h \ $(TOP)/src/where.c @@ -154,6 +155,12 @@ HDR = \ $(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. # @@ -185,10 +192,10 @@ sqlite: $(TOP)/src/shell.c libsqlite.la sqlite.h # files are automatically generated. This target takes care of # all that automatic generation. # -target_source: $(SRC) $(HDR) +target_source: $(SRC) $(VDBEHDR) 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 @@ -268,9 +275,12 @@ tokenize.lo: $(TOP)/src/tokenize.c $(HDR) util.lo: $(TOP)/src/util.c $(HDR) $(LIBTOOL) $(TCC) -c $(TOP)/src/util.c -vdbe.lo: $(TOP)/src/vdbe.c $(HDR) +vdbe.lo: $(TOP)/src/vdbe.c $(VDBEHDR) $(LIBTOOL) $(TCC) -c $(TOP)/src/vdbe.c +vdbeaux.lo: $(TOP)/src/vdbe.c $(VDBEHDR) + $(LIBTOOL) $(TCC) -c $(TOP)/src/vdbeaux.c + where.lo: $(TOP)/src/where.c $(HDR) $(LIBTOOL) $(TCC) -c $(TOP)/src/where.c diff --git a/manifest b/manifest index b17a98bdc9..c222ede818 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -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 +C Update\sMakefile.in\sfor\sthe\snew\svdbeaux.c\sfile.\s\sRemove\sthe\sexperimental\n"sqlite_instantiate()"\sroutine\sand\sreplace\sit\swith\s"sqlite_bind()"\swhich\nis\smore\slike\sODBC\sand\sJDBC.\s(CVS\s1095) +D 2003-09-06T22:18:08 +F Makefile.in 0cf2ffb6dc35694895e0dac488bc1259b6a4eb90 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F VERSION 97d209249f825001288ff942df07b48e1083af5c @@ -26,45 +26,45 @@ F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6 F src/btree.c ba1cc0c71c3d2742b9a9047832335dc7d3656c45 F src/btree.h 9b7c09f1e64274d7bb74a57bbfc63778f67b1048 F src/btree_rb.c 550ce12841a87380554abae4442571567463de3a -F src/build.c 7cdc95266496f53673a66202477b137d514898cf +F src/build.c 9def3a3b8fba59325ed686049b88c2e7aff9af12 F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73 F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc F src/encode.c 25ea901a9cefb3d93774afa4a06b57cb58acf544 -F src/expr.c 0c10a35c15756e90940d946cdec1e5c7d860ddc9 +F src/expr.c 8acdc2f7b2e756fc62336c728ab6a579979a5719 F src/func.c 377ea94127351de27892a62a63f931e0fbaa33d4 F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c dc200ae04a36bd36e575272a069e20c528b7fbdf -F src/main.c e472b0c86b811a76b6a17760c945acfabd8ba935 +F src/main.c ae92469674db9987de2848e373cd41a394621e32 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c 97df440bc71f65e22df5d3d920ce39551c0a5f5a F src/os.h 729395fefcca4b81ae056aa9ff67b72bb40dd9e0 F src/pager.c 62702dff51d50694d039bc210f31990d1fbba2dd F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31 -F src/parse.y 5cd707f0e5444b1dd168e414dd2c055fb158db5c +F src/parse.y 121daf2125dc2023029398a2ef38feb86cb5306a 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 72c07cf3b70c42a0e829270527f7b40a55d4a2d6 -F src/sqliteInt.h e68eb1eeba806905acc9ed491f4c5b96587020df +F src/sqlite.h.in f8ae61546942e5a81df0ce3118048bec8dc87be4 +F src/sqliteInt.h 8901c15945b3b0f7ef4c13ebbc2deeb4765014d5 F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95 F src/tclsqlite.c ec9e5b796bf9ec1483927e986828a205d4a7422a -F src/test1.c 751e11106c637d8ee64ecf95597b0133c544ab9f +F src/test1.c f9d5816610f7ec4168ab7b098d5207a5708712b6 F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e -F src/tokenize.c ea4e89b37db050fb99ae4c916bd7671375845aaf +F src/tokenize.c 74152bde07da0623aaa60fb6ab71d5af1c035546 F src/trigger.c 474581eaab388233df01bb019e558af2965decbf F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397 F src/util.c f16efa2d60bfd4e31ae06b07ed149557e828d294 F src/vacuum.c e4724eade07e4cf8897060a8cf632dbd92408eeb -F src/vdbe.c 00c547e77d4100b6671c1509df5993ab315a166c -F src/vdbe.h 3c51cb382316dbf3860e4ece72e658b4bf014501 -F src/vdbeInt.h 15cd01061b2f0acb967bdc5195fe1e891bb707a1 -F src/vdbeaux.c ebf5eab163fa8435e4fc24bcebe4eab4147d871b +F src/vdbe.c 4570d4361838327f45aa3788034e108c048b4d3f +F src/vdbe.h 3957844e46fea71fd030e78f6a3bd2f7e320fb43 +F src/vdbeInt.h 2824bf88895b901b3a8c9e44527c67530e1c0dcb +F src/vdbeaux.c 402daaa4f9c861a5182c47456d372715d2cd571f F src/where.c 83b2a2d26d5c3bea33457a83e541bb1dcf7b1248 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test c26848402e7ac829e043e1fa5e0eb87032e5d81d @@ -172,7 +172,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P 912f47c72d3597c6d5acff765d94922bd660339a -R 197956f145d2d77ab02def05dccb6402 +P bfd69391d3d63675f206ffd8ff0401ea1cbcc073 +R dac64908088b314675a59ad2bf8654f6 U drh -Z 7934264d068323cc21204d69f10c800f +Z 438620e1ac865f39fe826e6f5d8d262a diff --git a/manifest.uuid b/manifest.uuid index f05e5965d6..1c5118ebd2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bfd69391d3d63675f206ffd8ff0401ea1cbcc073 \ No newline at end of file +990bb11898a539bb0795a4a216fcd989943a0fb2 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 560fc305ea..0e214676d4 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.159 2003/08/24 16:38:18 drh Exp $ +** $Id: build.c,v 1.160 2003/09/06 22:18:08 drh Exp $ */ #include "sqliteInt.h" #include @@ -51,6 +51,7 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){ DbClearProperty(db, i, DB_Cookie); } } + pParse->nVar = 0; } /* @@ -86,7 +87,8 @@ void sqliteExec(Parse *pParse){ if( v && pParse->nErr==0 ){ FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqliteVdbeTrace(v, trace); - sqliteVdbeMakeReady(v, xCallback, pParse->pArg, pParse->explain); + sqliteVdbeMakeReady(v, pParse->nVar, xCallback, pParse->pArg, + pParse->explain); if( pParse->useCallback ){ if( pParse->explain ){ rc = sqliteVdbeList(v); @@ -110,6 +112,7 @@ void sqliteExec(Parse *pParse){ pParse->nMem = 0; pParse->nSet = 0; pParse->nAgg = 0; + pParse->nVar = 0; } /* diff --git a/src/expr.c b/src/expr.c index 46bd04d471..398bf8f629 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.99 2003/09/06 01:10:47 drh Exp $ +** $Id: expr.c,v 1.100 2003/09/06 22:18:08 drh Exp $ */ #include "sqliteInt.h" #include @@ -1046,7 +1046,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ break; } case TK_VARIABLE: { - sqliteVdbeAddOp(v, OP_Variable, atoi(&pExpr->token.z[1]), 0); + sqliteVdbeAddOp(v, OP_Variable, pExpr->iTable, 0); break; } case TK_LT: diff --git a/src/main.c b/src/main.c index 29a4d2ca0d..1b0c692e8a 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.141 2003/09/06 01:10:47 drh Exp $ +** $Id: main.c,v 1.142 2003/09/06 22:18:08 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -695,31 +695,6 @@ 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 @@ -753,7 +728,7 @@ int sqlite_reset( char **pzErrMsg /* OUT: Write error messages here */ ){ int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg); - sqliteVdbeMakeReady((Vdbe*)pVm, 0, 0, 0); + sqliteVdbeMakeReady((Vdbe*)pVm, -1, 0, 0, 0); sqliteStrRealloc(pzErrMsg); return rc; } @@ -790,6 +765,7 @@ const char *sqlite_error_string(int rc){ case SQLITE_NOLFS: z = "kernel lacks large file support"; break; case SQLITE_AUTH: z = "authorization denied"; break; case SQLITE_FORMAT: z = "auxiliary database format error"; break; + case SQLITE_RANGE: z = "bind index out of range"; break; default: z = "unknown error"; break; } return z; diff --git a/src/parse.y b/src/parse.y index 5ea4f410f3..21c033b103 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.100 2003/09/06 01:10:48 drh Exp $ +** @(#) $Id: parse.y,v 1.101 2003/09/06 22:18:08 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -541,7 +541,10 @@ 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) ::= VARIABLE(X). { + A = sqliteExpr(TK_VARIABLE, 0, 0, &X); + if( A ) A->iTable = ++pParse->nVar; +} 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 bcf8b38a2b..3832ee6b9d 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.51 2003/09/06 01:10:48 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.52 2003/09/06 22:18:08 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -166,6 +166,7 @@ int sqlite_exec( #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_RANGE 25 /* 2nd parameter to sqlite_bind out of range */ #define SQLITE_ROW 100 /* sqlite_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite_step() has finished executing */ @@ -695,31 +696,38 @@ int sqlite_finalize(sqlite_vm*, char **pzErrMsg); ** ** If sqlite_reset() returns SQLITE_SCHEMA, then *ppVm is set to NULL. ** +******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** */ -int sqlite_reset(sqlite_vm *, char **pzErrMsg); +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. +** If the SQL that was handed to sqlite_compile contains variables that +** are represeted in the SQL text by a question mark ('?'). This routine +** is used to assign values to those variables. +** +** The first parameter is a virtual machine obtained from sqlite_compile(). +** The 2nd "idx" parameter determines which variable in the SQL statement +** to bind the value to. The left most '?' is 1. The 3rd parameter is +** the value to assign to that variable. The 4th parameter is the number +** of bytes in the value, including the terminating \000 for strings. +** Finally, the 5th "copy" parameter is TRUE if SQLite should make its +** own private copy of this value, or false if the space that the 3rd +** parameter points to will be unchanging and can be used directly by +** SQLite. +** +** Unbound variables are treated as having a value of NULL. To explicitly +** set a variable to NULL, call this routine with the 3rd parameter as a +** NULL pointer. +** +** If the 4th "len" parameter is -1, then strlen() is used to find the +** length. ** ** 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_instantiate(sqlite_vm*, int, const char**); - - +int sqlite_bind(sqlite_vm*, int idx, const char *value, int len, int copy); #ifdef __cplusplus } /* End of the 'extern "C"' block */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 65944bec8f..500bcf4751 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.197 2003/08/23 22:40:54 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.198 2003/09/06 22:18:08 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -604,7 +604,9 @@ struct Token { ** it can be accessed after all aggregates are computed. ** ** If the expression is a function, the Expr.iTable is an integer code -** representing which function. +** representing which function. If the expression is an unbound variable +** marker (a question mark character '?' in the original SQL) then the +** Expr.iTable holds the index number for that variable. ** ** The Expr.pSelect field points to a SELECT statement. The SELECT might ** be the right operand of an IN operator. Or, if a scalar SELECT appears @@ -866,6 +868,7 @@ struct Parse { int nMem; /* Number of memory cells used so far */ int nSet; /* Number of sets used so far */ int nAgg; /* Number of aggregate expressions */ + int nVar; /* Number of '?' variables seen in the SQL so far */ AggExpr *aAgg; /* An array of aggregate expressions */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ diff --git a/src/test1.c b/src/test1.c index d768d3440c..e8af1fc8f2 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.27 2003/09/06 01:10:48 drh Exp $ +** $Id: test1.c,v 1.28 2003/09/06 22:18:08 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -806,11 +806,22 @@ static int test_reset( } /* -** Usage: sqlite_instantiate VM ARGS... -** -** Set the values of variables (ex: $1, $2, etc) in the original SQL string. +** This is the "static_bind_value" that variables are bound to when +** the FLAG option of sqlite_bind is "static" */ -static int test_instantiate( +static char *sqlite_static_bind_value = 0; + +/* +** Usage: sqlite_bind VM IDX VALUE FLAGS +** +** Sets the value of the IDX-th occurance of "?" in the original SQL +** string. VALUE is the new value. If FLAGS=="null" then VALUE is +** ignored and the value is set to NULL. If FLAGS=="static" then +** the value is set to the value of a static variable named +** "sqlite_static_bind_value". If FLAGS=="normal" then a copy +** of the VALUE is made. +*/ +static int test_bind( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ @@ -818,13 +829,25 @@ static int test_instantiate( ){ sqlite_vm *vm; int rc; - if( argc<2 ){ + int idx; + if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " VM ARGS...\"", 0); + " VM IDX VALUE (null|static|normal)\"", 0); return TCL_ERROR; } if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; - rc = sqlite_instantiate(vm, argc-2, &argv[2]); + if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; + if( strcmp(argv[4],"null")==0 ){ + rc = sqlite_bind(vm, idx, 0, 0, 0); + }else if( strcmp(argv[4],"static")==0 ){ + rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0); + }else if( strcmp(argv[4],"normal")==0 ){ + rc = sqlite_bind(vm, idx, argv[3], -1, 1); + }else{ + Tcl_AppendResult(interp, "4th argument should be " + "\"null\" or \"static\" or \"normal\"", 0); + return TCL_ERROR; + } if( rc ){ char zBuf[50]; sprintf(zBuf, "(%d) ", rc); @@ -887,7 +910,7 @@ 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_bind", (Tcl_CmdProc*)test_bind }, { "sqlite_reset", (Tcl_CmdProc*)test_reset }, { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, }; @@ -900,5 +923,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ (char*)&sqlite_search_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_open_file_count", (char*)&sqlite_open_file_count, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite_static_bind_value", + (char*)&sqlite_static_bind_value, TCL_LINK_STRING); return TCL_OK; } diff --git a/src/tokenize.c b/src/tokenize.c index 7a187186e6..24433a07fa 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.61 2003/09/06 01:10:48 drh Exp $ +** $Id: tokenize.c,v 1.62 2003/09/06 22:18:08 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -380,11 +380,9 @@ 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++){} + case '?': { *tokenType = TK_VARIABLE; - return i; + return 1; } default: { if( !isIdChar[*z] ){ diff --git a/src/vdbe.c b/src/vdbe.c index 305168dfca..e1f1154a49 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,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.239 2003/09/06 20:12:01 drh Exp $ +** $Id: vdbe.c,v 1.240 2003/09/06 22:18:08 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -711,14 +711,17 @@ case OP_String: { ** ** 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(). +** Any occurance of the '?' character in the original SQL is considered +** a variable. Variables in the SQL string are number from left to +** right beginning with 1. The values of variables are set using the +** sqlite_bind() API. */ 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; + int j = pOp->p1 - 1; + if( j>=0 && jnVar && p->azVar[j]!=0 ){ + zStack[i] = p->azVar[j]; + aStack[i].n = p->anVar[j]; aStack[i].flags = STK_Str | STK_Static; }else{ zStack[i] = 0; diff --git a/src/vdbe.h b/src/vdbe.h index 494313dcb4..87fea2517f 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.67 2003/09/06 01:10:49 drh Exp $ +** $Id: vdbe.h,v 1.68 2003/09/06 22:18:08 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -84,7 +84,7 @@ int sqliteVdbeFindOp(Vdbe*, int, int); VdbeOp *sqliteVdbeGetOp(Vdbe*, int); int sqliteVdbeMakeLabel(Vdbe*); void sqliteVdbeDelete(Vdbe*); -void sqliteVdbeMakeReady(Vdbe*,sqlite_callback,void*,int); +void sqliteVdbeMakeReady(Vdbe*,int,sqlite_callback,void*,int); int sqliteVdbeExec(Vdbe*); int sqliteVdbeList(Vdbe*); int sqliteVdbeFinalize(Vdbe*,char**); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 20aebdb4fa..d168387cd2 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -235,8 +235,10 @@ 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 */ + int nVar; /* Number of entries in azVariable[] */ + char **azVar; /* Values for the OP_Variable opcode */ + int *anVar; /* Length of each value in azVariable[] */ + u8 *abVar; /* TRUE if azVariable[i] needs to be sqliteFree()ed */ char *zLine; /* A single line from the input file */ int nLineAlloc; /* Number of spaces allocated for zLine */ int magic; /* Magic number for sanity checking */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 9fedb8dd0b..dd67376329 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -568,6 +568,7 @@ int sqliteVdbeList( */ void sqliteVdbeMakeReady( Vdbe *p, /* The VDBE */ + int nVar, /* Number of '?' see in the SQL statement */ sqlite_callback xCallback, /* Result callback */ void *pCallbackArg, /* 1st argument to xCallback() */ int isExplain /* True if the EXPLAIN keywords is present */ @@ -591,10 +592,17 @@ void sqliteVdbeMakeReady( ** ** Allocation all the stack space we will ever need. */ + p->nVar = nVar>=0 ? nVar : p->nVar; n = isExplain ? 10 : p->nOp; - p->aStack = sqliteMalloc( n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) ); + p->aStack = sqliteMalloc( + n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) /* aStack and zStack */ + + p->nVar*(sizeof(char*)+sizeof(int)+1) /* azVar, anVar, abVar */ + ); p->zStack = (char**)&p->aStack[n]; p->azColName = (char**)&p->zStack[n]; + p->azVar = (char**)&p->azColName[n]; + p->anVar = (int*)&p->azVar[p->nVar]; + p->abVar = (u8*)&p->anVar[p->nVar]; sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0); p->agg.pSearch = 0; @@ -739,15 +747,6 @@ static void closeAllCursors(Vdbe *p){ 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. ** @@ -808,7 +807,6 @@ static void Cleanup(Vdbe *p){ } sqliteFree(p->zErrMsg); p->zErrMsg = 0; - ClearVariableArray(p); } /* @@ -927,37 +925,33 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ ** ** 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 ){ +int sqlite_bind(sqlite_vm *pVm, int i, const char *zVal, int len, int copy){ + Vdbe *p = (Vdbe*)pVm; + if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 ){ return SQLITE_MISUSE; } - ClearVariableArray(p); - if( nValue==0 ){ - p->nVariable = 0; - p->azVariable = 0; + if( i<1 || i>p->nVar ){ + return SQLITE_RANGE; } - for(i=n=0; iabVar[i] ){ + sqliteFree(p->azVar[i]); } - p->azVariable = sqliteMalloc( sizeof(p->azVariable[0])*nValue + n ); - if( p->azVariable==0 ){ - p->nVariable = 0; - return SQLITE_NOMEM; + if( zVal==0 ){ + copy = 0; + len = 0; } - 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; - } + if( len<0 ){ + len = strlen(zVal)+1; } - p->nVariable = nValue; + if( copy ){ + p->azVar[i] = sqliteMalloc( len ); + if( p->azVar[i] ) memcpy(p->azVar[i], zVal, len); + }else{ + p->azVar[i] = zVal; + } + p->abVar[i] = copy; + p->anVar[i] = len; return SQLITE_OK; } @@ -988,6 +982,9 @@ void sqliteVdbeDelete(Vdbe *p){ sqliteFree(p->aOp[i].p3); } } + for(i=0; inVar; i++){ + if( p->abVar[i] ) sqliteFree(p->azVar[i]); + } sqliteFree(p->aOp); sqliteFree(p->aLabel); sqliteFree(p->aStack);