-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
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
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
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
-a2715b049a86555990abccc7aa363c524ddb9982
\ No newline at end of file
+b7f1fc26d24012e1e7c7f6b3cc0b84ad2b02b8ad
\ No newline at end of file
*/
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;
}
/*
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;
}
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;
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; i<nVal; i++){
+ rc = sqlite3ValueFromExpr(db, pList->a[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<nVal; i++){
+ sqlite3ValueFree(apVal[i]);
+ }
+ sqlite3DbFree(db, apVal);
+
+ *ppVal = pVal;
+ return rc;
+}
+#else
+# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
+#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
+
/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
}
#endif
+ else if( op==TK_FUNCTION ){
+ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
+ }
+
*ppVal = pVal;
return rc;
--- /dev/null
+# 2015-03-12
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# Test that deterministic scalar functions passed constant arguments
+# are used with stat4 data.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set ::testprefix analyzeF
+
+ifcapable {!stat4} {
+ finish_test
+ return
+}
+
+proc isqrt {i} { expr { int(sqrt($i)) } }
+db func isqrt isqrt
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(x INTEGER, y INTEGER);
+ WITH data(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM data
+ )
+ INSERT INTO t1 SELECT isqrt(i), isqrt(i) FROM data LIMIT 400;
+ CREATE INDEX t1x ON t1(x);
+ CREATE INDEX t1y ON t1(y);
+ ANALYZE;
+}
+
+proc str {a} { return $a }
+db func str str
+
+# Note: tests 7 to 12 might be unstable - as they assume SQLite will
+# prefer the expression to the right of the AND clause. Which of
+# course could change.
+#
+# Note 2: tests 9 and 10 depend on the tcl interface creating functions
+# without the SQLITE_DETERMINISTIC flag set.
+#
+foreach {tn where idx} {
+ 1 "x = 4 AND y = 19" {t1x (x=?)}
+ 2 "x = 19 AND y = 4" {t1y (y=?)}
+ 3 "x = '4' AND y = '19'" {t1x (x=?)}
+ 4 "x = '19' AND y = '4'" {t1y (y=?)}
+ 5 "x = substr('5195', 2, 2) AND y = substr('145', 2, 1)" {t1y (y=?)}
+ 6 "x = substr('145', 2, 1) AND y = substr('5195', 2, 2)" {t1x (x=?)}
+
+ 7 "x = substr('5195', 2, 2+0) AND y = substr('145', 2, 1+0)" {t1y (y=?)}
+ 8 "x = substr('145', 2, 1+0) AND y = substr('5195', 2, 2+0)" {t1y (y=?)}
+
+ 9 "x = str('19') AND y = str('4')" {t1y (y=?)}
+ 10 "x = str('4') AND y = str('19')" {t1y (y=?)}
+
+ 11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)}
+ 12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)}
+} {
+ set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}"
+ do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res
+}
+
+do_catchsql_test 2.1 {
+ SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
+} {1 {no such function: func}}
+do_catchsql_test 2.2 {
+ UPDATE t1 SET y=y+1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
+} {1 {no such function: func}}
+
+
+finish_test
+