From: dan Date: Wed, 11 Mar 2015 20:06:40 +0000 (+0000) Subject: Allow the query planner to evaluate deterministic scalar SQL functions used in WHERE... X-Git-Tag: version-3.8.9~81^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=18bf80768934fe2f610de8eb8334806a73c181ff;p=thirdparty%2Fsqlite.git Allow the query planner to evaluate deterministic scalar SQL functions used in WHERE constraints if all arguments are SQL literals in order to compare the results with sqlite_stat4 sample data. FossilOrigin-Name: b7f1fc26d24012e1e7c7f6b3cc0b84ad2b02b8ad --- diff --git a/manifest b/manifest index abbbe02140..60c76c5cba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Expand\sthe\smulti-process\stest\scases\sto\srepeat\seach\scase\s20\stimes\sand\nto\srepeat\stests\susing\sdifferent\sjournal\smodes. -D 2015-03-11T14:34:38.239 +C Allow\sthe\squery\splanner\sto\sevaluate\sdeterministic\sscalar\sSQL\sfunctions\sused\sin\sWHERE\sconstraints\sif\sall\sarguments\sare\sSQL\sliterals\sin\sorder\sto\scompare\sthe\sresults\swith\ssqlite_stat4\ssample\sdata. +D 2015-03-11T20:06:40.904 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -296,10 +296,10 @@ F src/vacuum.c 9460b9de7b2d4e34b0d374894aa6c8a0632be8ec F src/vdbe.c 94cbc2115075b1a562a2a702c29ba48e74f85d34 F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h bb56fd199d8af1a2c1b9639ee2f70724b4338e3a -F src/vdbeapi.c dac0d0d8009a8aa549cd77d9c29da44c0344f0c4 +F src/vdbeapi.c 5c207659c8a57c12c3f77a8fb97544e032fc2f14 F src/vdbeaux.c 97911edb61074b871ec4aa2d6bb779071643dee5 F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 -F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f +F src/vdbemem.c 8572106eb3b64ad6e02698c0fb312ccb47bb5c9e F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 699f2b8d509cfe379c33dde33827875d5b030e01 @@ -333,6 +333,7 @@ F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594 F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d +F test/analyzeF.test 299a47183c648d8ad92671f313def8fd7cb09875 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 @@ -1241,7 +1242,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 8d0b11c96e15556dd65ced05708a832aef134e69 -R 2327229d01e481a57e92de598065db5c -U drh -Z cd1fd5866edba6a7b1ae8e17fb546b84 +P a2715b049a86555990abccc7aa363c524ddb9982 +R 8289f5b5a84378b5cf3294cc8646b1fb +T *branch * stat4-function +T *sym-stat4-function * +T -sym-trunk * +U dan +Z a4cf4e61f3250d5413e8887a5d5cd094 diff --git a/manifest.uuid b/manifest.uuid index 57b677aa08..28f0ab069b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a2715b049a86555990abccc7aa363c524ddb9982 \ No newline at end of file +b7f1fc26d24012e1e7c7f6b3cc0b84ad2b02b8ad \ No newline at end of file diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 8c0038e4e8..fc3d60f20b 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -637,12 +637,13 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ */ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ Vdbe *v = p->pVdbe; + sqlite3_int64 iTime = 0; int rc; - if( v->iCurrentTime==0 ){ - rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime); - if( rc ) v->iCurrentTime = 0; - } - return v->iCurrentTime; + if( v && v->iCurrentTime ) return v->iCurrentTime; + rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &iTime); + if( rc ) return 0; + if( v ) v->iCurrentTime = iTime; + return iTime; } /* @@ -712,6 +713,7 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + if( pCtx->pVdbe==0 ) return 0; for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; } @@ -735,6 +737,7 @@ void sqlite3_set_auxdata( assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( iArg<0 ) goto failed; + if( pVdbe==0 ) goto failed; for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; diff --git a/src/vdbemem.c b/src/vdbemem.c index 870fb5bd89..ce7b73deac 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1134,6 +1134,128 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ return sqlite3ValueNew(db); } +/* +** The expression object indicated by the second argument is guaranteed +** to be a scalar SQL function. If +** +** * all function arguments are SQL literals, +** * the SQLITE_FUNC_CONSTANT function flag is set, +** * the SQLITE_FUNC_NEEDCOLL function flag is not set, and +** * this routine is being invoked as part of examining stat4 data, +** not as part of handling a default value on a column created using +** ALTER TABLE ADD COLUMN, +** +** then this routine attempts to invoke the SQL function. Assuming no +** error occurs, output parameter (*ppVal) is set to point to a value +** object containing the result before returning SQLITE_OK. +** +** Affinity aff is applied to the result of the function before returning. +** If the result is a text value, the sqlite3_value object uses encoding +** enc. +** +** If the conditions above are not met, this function returns SQLITE_OK +** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to +** NULL and an SQLite error code returned. +*/ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +static int valueFromFunction( + sqlite3 *db, /* The database connection */ + Expr *p, /* The expression to evaluate */ + u8 enc, /* Encoding to use */ + u8 aff, /* Affinity to use */ + sqlite3_value **ppVal, /* Write the new value here */ + struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ +){ + sqlite3_context ctx; /* Context object for function invocation */ + sqlite3_value **apVal = 0; /* Function arguments */ + int nVal = 0; /* Size of apVal[] array */ + FuncDef *pFunc = 0; /* Function definition */ + sqlite3_value *pVal = 0; /* New value */ + int rc = SQLITE_OK; /* Return code */ + int nName; /* Size of function name in bytes */ + ExprList *pList; /* Function arguments */ + int i; /* Iterator variable */ + + /* If pCtx==0, then this is probably being called to to obtain an + ** sqlite3_value object for the default value of a column. In that case + ** function expressions are not supported. Function expressions are + ** only supported when extracting values to compare with sqlite_stat4 + ** records. + ** + ** It may also be that this function expression is an argument passed + ** to another function expression. As in "f2(...)" within the query: + ** + ** SELECT * FROM tbl WHERE tbl.c = f1(0, f2(...), 1); + ** + ** For now, extracting the value of "f1(...)" is not supported either. + */ + if( pCtx==0 ) return SQLITE_OK; + + assert( (p->flags & (EP_TokenOnly|EP_Reduced))==0 ); + pList = p->x.pList; + if( pList ) nVal = pList->nExpr; + nName = sqlite3Strlen30(p->u.zToken); + pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0); + assert( pFunc ); + if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0 + || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) + ){ + return SQLITE_OK; + } + + if( pList ){ + apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal); + if( apVal==0 ){ + rc = SQLITE_NOMEM; + goto value_from_function_out; + } + for(i=0; ia[i].pExpr, enc, aff, &apVal[i]); + if( apVal[i]==0 ) goto value_from_function_out; + assert( rc==SQLITE_OK ); + } + } + + pVal = valueNew(db, pCtx); + if( pVal==0 ){ + rc = SQLITE_NOMEM; + goto value_from_function_out; + } + + memset(&ctx, 0, sizeof(ctx)); + ctx.pOut = pVal; + ctx.pFunc = pFunc; + pFunc->xFunc(&ctx, nVal, apVal); + if( ctx.isError ){ + rc = ctx.isError; + sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); + }else{ + sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); + if( rc==SQLITE_OK ){ + rc = sqlite3VdbeChangeEncoding(pVal, enc); + } + if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){ + rc = SQLITE_TOOBIG; + } + } + + value_from_function_out: + if( rc!=SQLITE_OK ){ + if( pCtx==0 ) sqlite3ValueFree(pVal); + pVal = 0; + } + for(i=0; i