From: drh Date: Fri, 23 Dec 2016 03:59:31 +0000 (+0000) Subject: Use the VList object to replace Parse.azVar for tracking the mapping between X-Git-Tag: version-3.16.0~27^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9bf755cc4467dd1e2d2fb8257f14ef974ec8bc41;p=thirdparty%2Fsqlite.git Use the VList object to replace Parse.azVar for tracking the mapping between SQL parameter names and parameter numbers. There is a performance improvement, though there are still a few hiccups in the current code. FossilOrigin-Name: 68ecafa1425a41358c88f41efea3262f1b4490f2 --- diff --git a/manifest b/manifest index a70672ab10..7c7b701cf1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings. -D 2016-12-22T14:53:25.934 +C Use\sthe\sVList\sobject\sto\sreplace\sParse.azVar\sfor\stracking\sthe\smapping\sbetween\nSQL\sparameter\snames\sand\sparameter\snumbers.\s\sThere\sis\sa\sperformance\nimprovement,\sthough\sthere\sare\sstill\sa\sfew\shiccups\sin\sthe\scurrent\scode. +D 2016-12-23T03:59:31.797 F Makefile.in 41bd4cad981487345c4a84081074bcdb876e4b2e F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da @@ -341,7 +341,7 @@ F src/ctime.c 9f2296a4e5d26ebf0e0d95a0af4628f1ea694e7a F src/date.c b48378aeac68fa20c811404955a9b62108df47d8 F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d F src/delete.c c8bc10d145c9666a34ae906250326fdaa8d58fa5 -F src/expr.c c7c11fbe8bd4d27d04f1370efcce5a05b4fca229 +F src/expr.c e640b1c82b0f22f6c00b75989b0c13503bd5083e F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae F src/func.c 43916c1d8e6da5d107d91d2b212577d4f69a876a @@ -393,7 +393,7 @@ F src/shell.c bf79a69d1f9b53de958498752b78e9906c5d0aff F src/sqlite.h.in e8e2d108d82647f0a812fdb74accf91c1ec08ddc F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae -F src/sqliteInt.h adbe80409c2926d91e5485789e5bf69313cd54b0 +F src/sqliteInt.h 2075e22d50833ca2d9956d0b7a6bfb845ad05dd2 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247 F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1 F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9 @@ -448,18 +448,18 @@ F src/test_windirent.c 600398db0198ca1c77ca183831bf456746b6f5c4 F src/test_windirent.h 7edc57e2faa727026dbd5d010dd0e2e665d5aa01 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c -F src/tokenize.c 6eb0752c4fd191f789190c3708ee5b0060fd2829 +F src/tokenize.c 5c2f516876fc27fbd7753913f032f49eb89e83b5 F src/treeview.c 4e44ade3bfe59d82005039f72e09333ce2b4162c F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182 F src/update.c 1da7c462110bffed442a42884cb0d528c1db46d8 F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c -F src/util.c e68e8ced7328f22d2cf7b4c898c394a0de34cdf1 +F src/util.c adf5ff9e457b69d3cab2afa45c9c4ce5da83da06 F src/vacuum.c 33c174b28886b2faf26e503b5a49a1c01a9b1c16 -F src/vdbe.c 0106e0d4f0d39aced35c150a6919d2878df6b1e0 +F src/vdbe.c 54b12d95dbf10533ab2584acbf31ae12b8bfe171 F src/vdbe.h 50ee139f9c68fff91be1d717ed3a6abbd496919c -F src/vdbeInt.h 42e498dbe96475dbb3fda3d85d8fd2a87eff60a2 -F src/vdbeapi.c 129a2a1103e29fe839e137c641ff42b8066667b5 -F src/vdbeaux.c 7f67112cc57b2fa37b777fbf03eb32c96b337cfe +F src/vdbeInt.h 281cb70332dc8b593b8c7afe776f3a2ba7d4255e +F src/vdbeapi.c d6ebaa465f070eb1af8ba4e7b34583ece87bdd24 +F src/vdbeaux.c 1e2840804828d32332565485b7faa755a3acabdb F src/vdbeblob.c f4f98ea672b242f807c08c92c7faaa79e5091b65 F src/vdbemem.c d3fd85b7b7ef3eb75de29c6d7e1d10d3ca78b4fd F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face @@ -1539,7 +1539,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 52a12e47de88744187bd1c71f2820885cde414a8 -R d04805544fe17af2729028773b1348a0 +P fa86db2f915c0a189c3be02b1aaa7f24d339d7d6 +R 4ff4f0f6aea9a4ccf6f07bfaa8f513d5 +T *branch * VList +T *sym-VList * +T -sym-trunk * U drh -Z 33ba125ec9059ffd904b774699d11e2c +Z d52e7f32e7ed6699ecd9b8a5a1a7ee92 diff --git a/manifest.uuid b/manifest.uuid index 2f4de5bfe2..f19d36a035 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fa86db2f915c0a189c3be02b1aaa7f24d339d7d6 \ No newline at end of file +68ecafa1425a41358c88f41efea3262f1b4490f2 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 60843bf52a..ae6107449d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -934,7 +934,7 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ ** variable number. ** ** Wildcards of the form "?nnn" are assigned the number "nnn". We make -** sure "nnn" is not too be to avoid a denial of service attack when +** sure "nnn" is not too big to avoid a denial of service attack when ** the SQL statement comes from an external source. ** ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number @@ -981,30 +981,13 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){ ** 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=x=0; inzVar; i++){ - if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){ - x = (ynVar)i+1; - break; - } + x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n); + if( x==0 ){ + x = (ynVar)(++pParse->nVar); + pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); } - if( x==0 ) x = (ynVar)(++pParse->nVar); } pExpr->iColumn = x; - if( x>pParse->nzVar ){ - char **a; - a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0])); - if( a==0 ){ - assert( db->mallocFailed ); /* Error reported through mallocFailed */ - return; - } - pParse->azVar = a; - memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0])); - pParse->nzVar = x; - } - if( pParse->azVar[x-1]==0 ){ - pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n); - } } if( pParse->nVar>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "too many SQL variables"); @@ -3430,9 +3413,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); if( pExpr->u.zToken[1]!=0 ){ - assert( pExpr->u.zToken[0]=='?' - || strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 ); - sqlite3VdbeAppendP4(v, pParse->azVar[pExpr->iColumn-1], P4_STATIC); + const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); + if( z ){ + assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 ); + sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); + } } return target; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 07156092c9..d78d2072de 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1046,6 +1046,14 @@ typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; typedef struct With With; +/* A VList object records a mapping between parameters/variables/wildcards +** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer +** variable number associated with that parameter. See the format description +** on the sqlite3VListAdd() routine for more information. A VList is really +** just an array of integers. +*/ +typedef int VList; + /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque @@ -2952,7 +2960,6 @@ struct Parse { Token sLastToken; /* The last token parsed */ ynVar nVar; /* Number of '?' variables seen in the SQL so far */ - int nzVar; /* Number of available slots in azVar[] */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -2964,7 +2971,7 @@ struct Parse { int iSelectId; /* ID of current select for EXPLAIN output */ int iNextSelectId; /* Next available select ID for EXPLAIN output */ #endif - char **azVar; /* Pointers to names of parameters */ + VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ @@ -3864,6 +3871,9 @@ LogEst sqlite3LogEstFromDouble(double); defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) u64 sqlite3LogEstToInt(LogEst); #endif +VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); +const char *sqlite3VListNumToName(VList*,int); +int sqlite3VListNameToNum(VList*,const char*,int); /* ** Routines to read and write variable-length integers. These used to diff --git a/src/tokenize.c b/src/tokenize.c index 0e60c56d66..c400dcd554 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -500,8 +500,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); - assert( pParse->nzVar==0 ); - assert( pParse->azVar==0 ); + assert( pParse->pVList==0 ); while( 1 ){ assert( i>=0 ); if( zSql[i]!=0 ){ @@ -588,8 +587,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); sqlite3DeleteTrigger(db, pParse->pNewTrigger); - for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]); - sqlite3DbFree(db, pParse->azVar); + sqlite3DbFree(db, pParse->pVList); while( pParse->pAinc ){ AutoincInfo *p = pParse->pAinc; pParse->pAinc = p->pNext; diff --git a/src/util.c b/src/util.c index a614f14619..5ece9226ff 100644 --- a/src/util.c +++ b/src/util.c @@ -1453,3 +1453,92 @@ u64 sqlite3LogEstToInt(LogEst x){ return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); } #endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ + +/* +** Add a new name/number pair to a VList. This might require that the +** VList object be reallocated, so return the new VList. If an OOM +** error occurs, the original VList freed, NULL is returned, and the +** db->mallocFailed flag is set. +** +** A VList is really just an array of integers. To destroy a VList, +** simply pass it to sqlite3DbFree(). +** +** The first integer is the number of integers allocated for the whole +** VList. The second integer is the number of integers actually used. +** Each name/number pair is encoded by subsequent groups of 3 or more +** integers. +** +** Each name/number pair starts with two integers which are the number +** value for the pair and the size of the name/number pair, respectively. +** The text name overlays one or more following integers. The text name +** is always zero-terminated. +** +*/ +VList *sqlite3VListAdd( + sqlite3 *db, /* The database connection used for malloc() */ + VList *pIn, /* The input VList. Might be NULL */ + const char *zName, /* Name of symbol to add */ + int nName, /* Bytes of text in zName */ + int iVal /* Value to associate with zName */ +){ + int nInt; /* number of sizeof(int) objects needed for zName */ + char *z; + int i; + + nInt = nName/4 + 3; + if( pIn==0 || pIn[1]+nInt > pIn[0] ){ + /* Enlarge the allocation */ + int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt; + VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); + if( pOut==0 ){ + sqlite3DbFree(db, pIn); + return 0; + } + if( pIn==0 ) pOut[1] = 2; + pIn = pOut; + pIn[0] = nAlloc; + } + i = pIn[1]; + pIn[i] = iVal; + pIn[i+1] = nInt; + z = (char*)&pIn[i+2]; + pIn[1] = i+nInt; + assert( pIn[1]<=pIn[0] ); + memcpy(z, zName, nName); + z[nName] = 0; + return pIn; +} + +/* +** Return a pointer to the name of a variable in the given VList that +** has the value iVal. Or return a NULL if there is no such variable in +** the list +*/ +const char *sqlite3VListNumToName(VList *pIn, int iVal){ + int i, mx; + if( pIn==0 ) return 0; + mx = pIn[1]; + i = 2; + do{ + if( pIn[i]==iVal ) return (char*)&pIn[i+2]; + i += pIn[i+1]; + }while( ip1>0 && pOp->p1<=p->nVar ); - assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] ); + assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index dbdde00edf..3e6bb06889 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -346,7 +346,6 @@ struct Vdbe { Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ Parse *pParse; /* Parsing context used to create this Vdbe */ ynVar nVar; /* Number of entries in aVar[] */ - ynVar nzVar; /* Number of entries in azVar[] */ u32 magic; /* Magic number for sanity checking */ int nMem; /* Number of memory locations currently allocated */ int nCursor; /* Number of slots in apCsr[] */ @@ -371,7 +370,7 @@ struct Vdbe { char *zErrMsg; /* Error message written here */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ - char **azVar; /* Name of variables */ + VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 213ba830d8..32794de9a0 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1470,10 +1470,8 @@ int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ */ const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ Vdbe *p = (Vdbe*)pStmt; - if( p==0 || i<1 || i>p->nzVar ){ - return 0; - } - return p->azVar[i-1]; + if( p==0 ) return 0; + return sqlite3VListNumToName(p->pVList, i); } /* @@ -1482,19 +1480,8 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ ** return 0. */ int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){ - int i; - if( p==0 ){ - return 0; - } - if( zName ){ - for(i=0; inzVar; i++){ - const char *z = p->azVar[i]; - if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){ - return i+1; - } - } - } - return 0; + if( p==0 || zName==0 ) return 0; + return sqlite3VListNameToNum(p->pVList, zName, nName); } int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName)); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index cfc07ba702..53aedf4983 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1975,10 +1975,8 @@ void sqlite3VdbeMakeReady( x.nFree = x.nNeeded; }while( !db->mallocFailed ); - p->nzVar = pParse->nzVar; - p->azVar = pParse->azVar; - pParse->nzVar = 0; - pParse->azVar = 0; + p->pVList = pParse->pVList; + pParse->pVList = 0; p->explain = pParse->explain; if( db->mallocFailed ){ p->nVar = 0; @@ -2982,8 +2980,7 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ } if( p->magic!=VDBE_MAGIC_INIT ){ releaseMemArray(p->aVar, p->nVar); - for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); - sqlite3DbFree(db, p->azVar); + sqlite3DbFree(db, p->pVList); sqlite3DbFree(db, p->pFree); } vdbeFreeOpArray(db, p->aOp, p->nOp);