1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Refactor the SQL parameter processing so that parameter names for values

that are optimized out of the prepare statement are not forgotten.

FossilOrigin-Name: b3aaf715b60b8a338cc6c92dad1ead4a3f7146a3
This commit is contained in:
drh
2011-06-01 18:15:55 +00:00
parent ed9624187d
commit 124c0b49a1
12 changed files with 202 additions and 208 deletions

View File

@@ -1,5 +1,5 @@
C Fix\sa\sproblem\sin\sthe\ssqlite3TestErrorName()\sfunction\s(used\sonly\sfor\stesting)\nthat\sappears\sto\shave\soriginated\sfrom\sa\sbad\smerge. C Refactor\sthe\sSQL\sparameter\sprocessing\sso\sthat\sparameter\snames\sfor\svalues\nthat\sare\soptimized\sout\sof\sthe\sprepare\sstatement\sare\snot\sforgotten.
D 2011-05-31T16:50:23.129 D 2011-06-01T18:15:55.858
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -125,13 +125,13 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 0d3b39dcb79565c053e35fc12713f12d8a74d6a9 F src/btree.c 0d3b39dcb79565c053e35fc12713f12d8a74d6a9
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3 F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
F src/build.c 0132bc6631fa617a1d28ef805921f6dbac18a514 F src/build.c c10ab9e2c77ade99dee23554787f8acfc0c231fc
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4 F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4
F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b
F src/delete.c cecc926c70783452f3e8eb452c728291ce1a0b21 F src/delete.c cecc926c70783452f3e8eb452c728291ce1a0b21
F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be F src/expr.c c33584bcf4ee011e28ff74e4dcef02da1dc09dd6
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91 F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91
F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc
@@ -179,9 +179,9 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff
F src/shell.c decd04236a7ef26be5ef46d4ea963044bfad9a48 F src/shell.c decd04236a7ef26be5ef46d4ea963044bfad9a48
F src/sqlite.h.in c095996e68e0082f674f32e68ca909fc24196a2a F src/sqlite.h.in 91c63a69eeddbd62182ec00dbfee390016972bdb
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
F src/sqliteInt.h d9ff5f198b5bac7ee0c6e1ea55f76897ba4dda87 F src/sqliteInt.h 6e58c558c57c8f44011736d5fa5295eb3130f9de
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -230,18 +230,18 @@ F src/test_vfs.c e7855568dfa1e0ba73668d273b65605d9f8b77e8
F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/tokenize.c 7b0c9281b2368dc69135e7a50bd271de9af1b467
F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8 F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8
F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f F src/update.c 5bcb56e5c7380a2eecb0e71891dbd4ad7437748f
F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70 F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70
F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e
F src/vdbe.c 103827f560cdc48b1d455ce4d4b3573dd88f9ab4 F src/vdbe.c 103827f560cdc48b1d455ce4d4b3573dd88f9ab4
F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbe.h d9c6123384189dc37d27beac1bf44688aa75b6cb
F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae F src/vdbeInt.h ad84226cc0adcb1185c22b70696b235a1678bb45
F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1 F src/vdbeapi.c 0eeadc75e44a30efd996d6af6e7c5a2488e35be8
F src/vdbeaux.c 99900868d18618a07ffaf780ecc41fd807834bde F src/vdbeaux.c 0505dc4f7ff3cf35e219fe0a20ab798a42772b8b
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
F src/vtab.c 9ba8c7fdb7d39260c033a402f6032d3e7bc5d336 F src/vtab.c 9ba8c7fdb7d39260c033a402f6032d3e7bc5d336
@@ -938,7 +938,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 701b8a23e3ea2c94454af5d9bd1e72acb66d0fe2 P a0ae314c7f41d0146a9ee1adc576cd977219a378
R 0252c62ef68072dedfcd687577c244b5 R d99e1065a540709b7ea760de89dbcfd0
U drh U drh
Z 32d78009c9e58634b2f842adf352a1be Z ce5ce2791f47aa05a4daaafded206f56

View File

@@ -1 +1 @@
a0ae314c7f41d0146a9ee1adc576cd977219a378 b3aaf715b60b8a338cc6c92dad1ead4a3f7146a3

View File

@@ -200,9 +200,7 @@ void sqlite3FinishCoding(Parse *pParse){
/* A minimum of one cursor is required if autoincrement is used /* A minimum of one cursor is required if autoincrement is used
* See ticket [a696379c1f08866] */ * See ticket [a696379c1f08866] */
if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem, sqlite3VdbeMakeReady(v, pParse);
pParse->nTab, pParse->nMaxArg, pParse->explain,
pParse->isMultiWrite && pParse->mayAbort);
pParse->rc = SQLITE_DONE; pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0; pParse->colNamesSet = 0;
}else{ }else{

View File

@@ -555,53 +555,53 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
/* Wildcard of the form "?". Assign the next variable number */ /* Wildcard of the form "?". Assign the next variable number */
assert( z[0]=='?' ); assert( z[0]=='?' );
pExpr->iColumn = (ynVar)(++pParse->nVar); pExpr->iColumn = (ynVar)(++pParse->nVar);
}else if( z[0]=='?' ){
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
** use it as the variable number */
i64 i;
int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
pExpr->iColumn = (ynVar)i;
testcase( i==0 );
testcase( i==1 );
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
}
if( i>pParse->nVar ){
pParse->nVar = (int)i;
}
}else{ }else{
/* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable ynVar x = 0;
** number as the prior appearance of the same name, or if the name u32 n = sqlite3Strlen30(z);
** has never appeared before, reuse the same variable number if( z[0]=='?' ){
*/ /* Wildcard of the form "?nnn". Convert "nnn" to an integer and
int i; ** use it as the variable number */
u32 n; i64 i;
n = sqlite3Strlen30(z); int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
for(i=0; i<pParse->nVarExpr; i++){ pExpr->iColumn = x = (ynVar)i;
Expr *pE = pParse->apVarExpr[i]; testcase( i==0 );
assert( pE!=0 ); testcase( i==1 );
if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){ testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
pExpr->iColumn = pE->iColumn; testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
break; if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
x = 0;
} }
if( i>pParse->nVar ){
pParse->nVar = (int)i;
}
}else{
/* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable
** number as the prior appearance of the same name, or if the name
** has never appeared before, reuse the same variable number
*/
ynVar i;
for(i=0; i<pParse->nzVar; i++){
if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
pExpr->iColumn = x = (ynVar)i+1;
break;
}
}
if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
} }
if( i>=pParse->nVarExpr ){ if( x>0 ){
pExpr->iColumn = (ynVar)(++pParse->nVar); if( x>pParse->nzVar ){
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ char **a;
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
pParse->apVarExpr = if( a==0 ) return; /* Error reported through db->mallocFailed */
sqlite3DbReallocOrFree( pParse->azVar = a;
db, memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
pParse->apVarExpr, pParse->nzVar = x;
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0])
);
} }
if( !db->mallocFailed ){ if( z[0]!='?' || pParse->azVar[x-1]==0 ){
assert( pParse->apVarExpr!=0 ); sqlite3DbFree(db, pParse->azVar[x-1]);
pParse->apVarExpr[pParse->nVarExpr++] = pExpr; pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
} }
} }
} }

View File

@@ -3068,8 +3068,6 @@ int sqlite3_bind_parameter_count(sqlite3_stmt*);
** is included as part of the name.)^ ** is included as part of the name.)^
** ^Parameters of the form "?" without a following integer have no name ** ^Parameters of the form "?" without a following integer have no name
** and are referred to as "nameless" or "anonymous parameters". ** and are referred to as "nameless" or "anonymous parameters".
** ^Any parameter that is optimized out of the prepared statement by the
** query planner becomes a nameless or anonymous parameter.
** **
** ^The first host parameter has an index of 1, not 0. ** ^The first host parameter has an index of 1, not 0.
** **

View File

@@ -2230,9 +2230,8 @@ struct Parse {
** each recursion */ ** each recursion */
int nVar; /* Number of '?' variables seen in the SQL so far */ int nVar; /* Number of '?' variables seen in the SQL so far */
int nVarExpr; /* Number of used slots in apVarExpr[] */ int nzVar; /* Number of available slots in azVar[] */
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */ char **azVar; /* Pointers to names of parameters */
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
int nAlias; /* Number of aliased result set columns */ int nAlias; /* Number of aliased result set columns */
int nAliasAlloc; /* Number of allocated slots for aAlias[] */ int nAliasAlloc; /* Number of allocated slots for aAlias[] */

View File

@@ -412,9 +412,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->pNewTable==0 ); assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 ); assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 ); assert( pParse->nVar==0 );
assert( pParse->nVarExpr==0 ); assert( pParse->nzVar==0 );
assert( pParse->nVarExprAlloc==0 ); assert( pParse->azVar==0 );
assert( pParse->apVarExpr==0 );
enableLookaside = db->lookaside.bEnabled; enableLookaside = db->lookaside.bEnabled;
if( db->lookaside.pStart ) db->lookaside.bEnabled = 1; if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
while( !db->mallocFailed && zSql[i]!=0 ){ while( !db->mallocFailed && zSql[i]!=0 ){
@@ -508,7 +507,8 @@ abort_parse:
} }
sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->apVarExpr); for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
sqlite3DbFree(db, pParse->azVar);
sqlite3DbFree(db, pParse->aAlias); sqlite3DbFree(db, pParse->aAlias);
while( pParse->pAinc ){ while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc; AutoincInfo *p = pParse->pAinc;

View File

@@ -185,7 +185,7 @@ int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*); void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*); int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int); void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*); int sqlite3VdbeCurrentAddr(Vdbe*);
@@ -194,6 +194,7 @@ int sqlite3VdbeCurrentAddr(Vdbe*);
void sqlite3VdbeTrace(Vdbe*,FILE*); void sqlite3VdbeTrace(Vdbe*,FILE*);
#endif #endif
void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeResetStepResult(Vdbe*);
void sqlite3VdbeRewind(Vdbe*);
int sqlite3VdbeReset(Vdbe*); int sqlite3VdbeReset(Vdbe*);
void sqlite3VdbeSetNumCols(Vdbe*,int); void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));

View File

@@ -287,11 +287,11 @@ struct Vdbe {
Mem *aVar; /* Values for the OP_Variable opcode. */ Mem *aVar; /* Values for the OP_Variable opcode. */
char **azVar; /* Name of variables */ char **azVar; /* Name of variables */
ynVar nVar; /* Number of entries in aVar[] */ ynVar nVar; /* Number of entries in aVar[] */
ynVar nzVar; /* Number of entries in azVar[] */
u32 cacheCtr; /* VdbeCursor row cache generation counter */ u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */ int pc; /* The program counter */
int rc; /* Value to return */ int rc; /* Value to return */
u8 errorAction; /* Recovery action to do in case of an error */ u8 errorAction; /* Recovery action to do in case of an error */
u8 okVar; /* True if azVar[] has been initialized */
u8 explain; /* True if EXPLAIN present on SQL command */ u8 explain; /* True if EXPLAIN present on SQL command */
u8 changeCntOn; /* True to update the change-counter */ u8 changeCntOn; /* True to update the change-counter */
u8 expired; /* True if the VM needs to be recompiled */ u8 expired; /* True if the VM needs to be recompiled */

View File

@@ -102,7 +102,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt; Vdbe *v = (Vdbe*)pStmt;
sqlite3_mutex_enter(v->db->mutex); sqlite3_mutex_enter(v->db->mutex);
rc = sqlite3VdbeReset(v); rc = sqlite3VdbeReset(v);
sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0); sqlite3VdbeRewind(v);
assert( (rc & (v->db->errMask))==rc ); assert( (rc & (v->db->errMask))==rc );
rc = sqlite3ApiExit(v->db, rc); rc = sqlite3ApiExit(v->db, rc);
sqlite3_mutex_leave(v->db->mutex); sqlite3_mutex_leave(v->db->mutex);
@@ -1167,32 +1167,6 @@ int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
return p ? p->nVar : 0; return p ? p->nVar : 0;
} }
/*
** Create a mapping from variable numbers to variable names
** in the Vdbe.azVar[] array, if such a mapping does not already
** exist.
*/
static void createVarMap(Vdbe *p){
if( !p->okVar ){
int j;
Op *pOp;
sqlite3_mutex_enter(p->db->mutex);
/* The race condition here is harmless. If two threads call this
** routine on the same Vdbe at the same time, they both might end
** up initializing the Vdbe.azVar[] array. That is a little extra
** work but it results in the same answer.
*/
for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
if( pOp->opcode==OP_Variable ){
assert( pOp->p1>0 && pOp->p1<=p->nVar );
p->azVar[pOp->p1-1] = pOp->p4.z;
}
}
p->okVar = 1;
sqlite3_mutex_leave(p->db->mutex);
}
}
/* /*
** Return the name of a wildcard parameter. Return NULL if the index ** Return the name of a wildcard parameter. Return NULL if the index
** is out of range or if the wildcard is unnamed. ** is out of range or if the wildcard is unnamed.
@@ -1201,10 +1175,9 @@ static void createVarMap(Vdbe *p){
*/ */
const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt; Vdbe *p = (Vdbe*)pStmt;
if( p==0 || i<1 || i>p->nVar ){ if( p==0 || i<1 || i>p->nzVar ){
return 0; return 0;
} }
createVarMap(p);
return p->azVar[i-1]; return p->azVar[i-1];
} }
@@ -1218,9 +1191,8 @@ int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
if( p==0 ){ if( p==0 ){
return 0; return 0;
} }
createVarMap(p);
if( zName ){ if( zName ){
for(i=0; i<p->nVar; i++){ for(i=0; i<p->nzVar; i++){
const char *z = p->azVar[i]; const char *z = p->azVar[i];
if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){ if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
return i+1; return i+1;

View File

@@ -1391,34 +1391,13 @@ static void *allocSpace(
} }
/* /*
** Prepare a virtual machine for execution. This involves things such ** Rewind the VDBE back to the beginning in preparation for
** as allocating stack space and initializing the program counter. ** running it.
** After the VDBE has be prepped, it can be executed by one or more
** calls to sqlite3VdbeExec().
**
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
** VDBE_MAGIC_RUN.
**
** This function may be called more than once on a single virtual machine.
** The first call is made while compiling the SQL statement. Subsequent
** calls are made as part of the process of resetting a statement to be
** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
** and isExplain parameters are only passed correct values the first time
** the function is called. On subsequent calls, from sqlite3_reset(), nVar
** is passed -1 and nMem, nCursor and isExplain are all passed zero.
*/ */
void sqlite3VdbeMakeReady( void sqlite3VdbeRewind(Vdbe *p){
Vdbe *p, /* The VDBE */ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
int nVar, /* Number of '?' see in the SQL statement */ int i;
int nMem, /* Number of memory cells to allocate */ #endif
int nCursor, /* Number of cursors to allocate */
int nArg, /* Maximum number of args in SubPrograms */
int isExplain, /* True if the EXPLAIN keywords is present */
int usesStmtJournal /* True to set Vdbe.usesStmtJournal */
){
int n;
sqlite3 *db = p->db;
assert( p!=0 ); assert( p!=0 );
assert( p->magic==VDBE_MAGIC_INIT ); assert( p->magic==VDBE_MAGIC_INIT );
@@ -1429,6 +1408,71 @@ void sqlite3VdbeMakeReady(
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */ /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
p->magic = VDBE_MAGIC_RUN; p->magic = VDBE_MAGIC_RUN;
#ifdef SQLITE_DEBUG
for(i=1; i<p->nMem; i++){
assert( p->aMem[i].db==p->db );
}
#endif
p->pc = -1;
p->rc = SQLITE_OK;
p->errorAction = OE_Abort;
p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->iStatement = 0;
p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
for(i=0; i<p->nOp; i++){
p->aOp[i].cnt = 0;
p->aOp[i].cycles = 0;
}
#endif
}
/*
** Prepare a virtual machine for execution for the first time after
** creating the virtual machine. 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 sqlite3VdbeExec().
**
** This function may be called exact once on a each virtual machine.
** After this routine is called the VM has been "packaged" and is ready
** to run. After this routine is called, futher calls to
** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
** the Vdbe from the Parse object that helped generate it so that the
** the Vdbe becomes an independent entity and the Parse object can be
** destroyed.
**
** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back
** to its initial state after it has been run.
*/
void sqlite3VdbeMakeReady(
Vdbe *p, /* The VDBE */
Parse *pParse /* Parsing context */
){
sqlite3 *db; /* The database connection */
int nVar; /* Number of parameters */
int nMem; /* Number of VM memory registers */
int nCursor; /* Number of cursors required */
int nArg; /* Number of arguments in subprograms */
int n; /* Loop counter */
u8 *zCsr; /* Memory available for allocation */
u8 *zEnd; /* First byte past allocated memory */
int nByte; /* How much extra memory is needed */
assert( p!=0 );
assert( p->nOp>0 );
assert( pParse!=0 );
assert( p->magic==VDBE_MAGIC_INIT );
db = p->db;
assert( db->mallocFailed==0 );
nVar = pParse->nVar;
nMem = pParse->nMem;
nCursor = pParse->nTab;
nArg = pParse->nMaxArg;
/* For each cursor required, also allocate a memory cell. Memory /* For each cursor required, also allocate a memory cell. Memory
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
** the vdbe program. Instead they are used to allocate space for ** the vdbe program. Instead they are used to allocate space for
@@ -1441,91 +1485,68 @@ void sqlite3VdbeMakeReady(
nMem += nCursor; nMem += nCursor;
/* Allocate space for memory registers, SQL variables, VDBE cursors and /* Allocate space for memory registers, SQL variables, VDBE cursors and
** an array to marshal SQL function arguments in. This is only done the ** an array to marshal SQL function arguments in.
** first time this function is called for a given VDBE, not when it is
** being called from sqlite3_reset() to reset the virtual machine.
*/ */
if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){ zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */
u8 *zCsr = (u8 *)&p->aOp[p->nOp]; /* Memory avaliable for alloation */ zEnd = (u8*)&p->aOp[p->nOpAlloc]; /* First byte past end of zCsr[] */
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; /* First byte past available mem */
int nByte; /* How much extra memory needed */
resolveP2Values(p, &nArg); resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)usesStmtJournal; p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( isExplain && nMem<10 ){ if( pParse->explain && nMem<10 ){
nMem = 10; nMem = 10;
}
memset(zCsr, 0, zEnd-zCsr);
zCsr += (zCsr - (u8*)0)&7;
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
/* Memory for registers, parameters, cursor, etc, is allocated in two
** passes. On the first pass, we try to reuse unused space at the
** end of the opcode array. If we are unable to satisfy all memory
** requirements by reusing the opcode array tail, then the second
** pass will fill in the rest using a fresh allocation.
**
** This two-pass approach that reuses as much memory as possible from
** the leftover space at the end of the opcode array can significantly
** reduce the amount of memory held by a prepared statement.
*/
do {
nByte = 0;
p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
&zCsr, zEnd, &nByte);
if( nByte ){
p->pFree = sqlite3DbMallocZero(db, nByte);
} }
memset(zCsr, 0, zEnd-zCsr); zCsr = p->pFree;
zCsr += (zCsr - (u8*)0)&7; zEnd = &zCsr[nByte];
assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); }while( nByte && !db->mallocFailed );
/* Memory for registers, parameters, cursor, etc, is allocated in two p->nCursor = (u16)nCursor;
** passes. On the first pass, we try to reuse unused space at the if( p->aVar ){
** end of the opcode array. If we are unable to satisfy all memory p->nVar = (ynVar)nVar;
** requirements by reusing the opcode array tail, then the second for(n=0; n<nVar; n++){
** pass will fill in the rest using a fresh allocation. p->aVar[n].flags = MEM_Null;
** p->aVar[n].db = db;
** This two-pass approach that reuses as much memory as possible from
** the leftover space at the end of the opcode array can significantly
** reduce the amount of memory held by a prepared statement.
*/
do {
nByte = 0;
p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
&zCsr, zEnd, &nByte);
if( nByte ){
p->pFree = sqlite3DbMallocZero(db, nByte);
}
zCsr = p->pFree;
zEnd = &zCsr[nByte];
}while( nByte && !db->mallocFailed );
p->nCursor = (u16)nCursor;
if( p->aVar ){
p->nVar = (ynVar)nVar;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
p->aVar[n].db = db;
}
}
if( p->aMem ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
for(n=1; n<=nMem; n++){
p->aMem[n].flags = MEM_Null;
p->aMem[n].db = db;
}
} }
} }
#ifdef SQLITE_DEBUG if( p->azVar ){
for(n=1; n<p->nMem; n++){ p->nzVar = pParse->nzVar;
assert( p->aMem[n].db==db ); memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
} }
#endif if( p->aMem ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->pc = -1; p->nMem = nMem; /* not from 0..nMem-1 */
p->rc = SQLITE_OK; for(n=1; n<=nMem; n++){
p->errorAction = OE_Abort; p->aMem[n].flags = MEM_Null;
p->explain |= isExplain; p->aMem[n].db = db;
p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->iStatement = 0;
p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
{
int i;
for(i=0; i<p->nOp; i++){
p->aOp[i].cnt = 0;
p->aOp[i].cycles = 0;
} }
} }
#endif p->explain = pParse->explain;
sqlite3VdbeRewind(p);
} }
/* /*
@@ -2399,6 +2420,7 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
*/ */
void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){ void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext; SubProgram *pSub, *pNext;
int i;
assert( p->db==0 || p->db==db ); assert( p->db==0 || p->db==db );
releaseMemArray(p->aVar, p->nVar); releaseMemArray(p->aVar, p->nVar);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
@@ -2407,6 +2429,7 @@ void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
sqlite3DbFree(db, pSub); sqlite3DbFree(db, pSub);
} }
for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
vdbeFreeOpArray(db, p->aOp, p->nOp); vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aLabel); sqlite3DbFree(db, p->aLabel);
sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->aColName);

View File

@@ -297,7 +297,10 @@ int sqlite3_blob_open(
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
sqlite3VdbeChangeP2(v, 7, pTab->nCol); sqlite3VdbeChangeP2(v, 7, pTab->nCol);
if( !db->mallocFailed ){ if( !db->mallocFailed ){
sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0, 0); pParse->nVar = 1;
pParse->nMem = 1;
pParse->nTab = 1;
sqlite3VdbeMakeReady(v, pParse);
} }
} }