When STAT4 is enabled, allow probes of the STAT4 table using the value

of constant functions computed at compile-time.

FossilOrigin-Name: 0f250957cd82be63e44eb99be6cc10760f4fdfc4
This commit is contained in:
drh 2015-03-12 21:22:08 +00:00
commit 3795f3cee3
7 changed files with 242 additions and 21 deletions

View File

@ -1,5 +1,5 @@
C Disable\smultiplexing\sof\smaster-journal\sfiles\sin\sthe\stest_multiplex.c\smodule. C When\sSTAT4\sis\senabled,\sallow\sprobes\sof\sthe\sSTAT4\stable\susing\sthe\svalue\nof\sconstant\sfunctions\scomputed\sat\scompile-time.
D 2015-03-12T19:12:30.098 D 2015-03-12T21:22:08.630
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -166,7 +166,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb F src/alter.c d23d6b6991f66b383934f137fd4384d93fb98c81
F src/analyze.c 91540f835163d5369ccbae78e2e6c74d0dd53c1d F src/analyze.c 91540f835163d5369ccbae78e2e6c74d0dd53c1d
F src/attach.c 880f9b8641a829c563e52dd13c452ce457ae4dd8 F src/attach.c 880f9b8641a829c563e52dd13c452ce457ae4dd8
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
@ -185,7 +185,7 @@ F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e
F src/expr.c 3ef111b88ae2941b84b6b6ea4be8d501ba1af0cb F src/expr.c 3ef111b88ae2941b84b6b6ea4be8d501ba1af0cb
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12 F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12
F src/func.c 44512c557d6d4a40e51f3980c5854ae3e92862d6 F src/func.c 1414c24c873c48796ad45942257a179a423ba42f
F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
@ -296,10 +296,10 @@ F src/vacuum.c 9460b9de7b2d4e34b0d374894aa6c8a0632be8ec
F src/vdbe.c a2725107658fd9572637e8e09d46dcfe851edb96 F src/vdbe.c a2725107658fd9572637e8e09d46dcfe851edb96
F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
F src/vdbeInt.h bb56fd199d8af1a2c1b9639ee2f70724b4338e3a F src/vdbeInt.h bb56fd199d8af1a2c1b9639ee2f70724b4338e3a
F src/vdbeapi.c dac0d0d8009a8aa549cd77d9c29da44c0344f0c4 F src/vdbeapi.c 1295402cabda4473ddee24955c8f7039514497e4
F src/vdbeaux.c 97911edb61074b871ec4aa2d6bb779071643dee5 F src/vdbeaux.c 97911edb61074b871ec4aa2d6bb779071643dee5
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbemem.c d52fa9f3bcf75d27d7b7846d81ee7898829c763d
F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2 F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2
F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
F src/vtab.c 699f2b8d509cfe379c33dde33827875d5b030e01 F src/vtab.c 699f2b8d509cfe379c33dde33827875d5b030e01
@ -333,6 +333,7 @@ F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594 F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594
F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d
F test/analyzeF.test 299a47183c648d8ad92671f313def8fd7cb09875
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
@ -1242,7 +1243,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 08958f57970d2346f3e98e62225e2b5d351d12d8 P b8684df395b5585a9428417c2bfd076515560f19 a991bb1a9eb54bdbd45bd623e8b304bdfeb481a3
R 0a12f0c8ae987d613ddb45d39ab86f14 R 8dac3425ac00e8cb91887f6600a4a803
U dan T +closed a991bb1a9eb54bdbd45bd623e8b304bdfeb481a3
Z 376d550a3accda483a2b851b4ef12904 U drh
Z f8e2642fd9bb84da1db25f0a4d97336b

View File

@ -1 +1 @@
b8684df395b5585a9428417c2bfd076515560f19 0f250957cd82be63e44eb99be6cc10760f4fdfc4

View File

@ -690,7 +690,10 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
*/ */
if( pDflt ){ if( pDflt ){
sqlite3_value *pVal = 0; sqlite3_value *pVal = 0;
if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){ int rc;
rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal);
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
if( rc!=SQLITE_OK ){
db->mallocFailed = 1; db->mallocFailed = 1;
return; return;
} }

View File

@ -22,7 +22,9 @@
** Return the collating function associated with a function. ** Return the collating function associated with a function.
*/ */
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
VdbeOp *pOp = &context->pVdbe->aOp[context->iOp-1]; VdbeOp *pOp;
assert( context->pVdbe!=0 );
pOp = &context->pVdbe->aOp[context->iOp-1];
assert( pOp->opcode==OP_CollSeq ); assert( pOp->opcode==OP_CollSeq );
assert( pOp->p4type==P4_COLLSEQ ); assert( pOp->p4type==P4_COLLSEQ );
return pOp->p4.pColl; return pOp->p4.pColl;

View File

@ -370,7 +370,7 @@ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode; pCtx->isError = errCode;
pCtx->fErrorOrAux = 1; pCtx->fErrorOrAux = 1;
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
pCtx->pVdbe->rcApp = errCode; if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif #endif
if( pCtx->pOut->flags & MEM_Null ){ if( pCtx->pOut->flags & MEM_Null ){
sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
@ -633,16 +633,27 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
} }
/* /*
** Return the current time for a statement ** Return the current time for a statement. If the current time
** is requested more than once within the same run of a single prepared
** statement, the exact same time is returned for each invocation regardless
** of the amount of time that elapses between invocations. In other words,
** the time returned is always the time of the first call.
*/ */
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
Vdbe *v = p->pVdbe;
int rc; int rc;
if( v->iCurrentTime==0 ){ sqlite3_int64 iTime = 0;
rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, &v->iCurrentTime); #ifndef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc ) v->iCurrentTime = 0; sqlite3_int64 *piTime = &iTime;
assert( p->pVdbe!=0 );
#else
sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime;
if( *piTime==0 )
#endif
{
rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime);
if( rc ) *piTime = 0;
} }
return v->iCurrentTime; return *piTime;
} }
/* /*
@ -712,6 +723,11 @@ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData; AuxData *pAuxData;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#if SQLITE_ENABLE_STAT3_OR_STAT4
if( pCtx->pVdbe==0 ) return 0;
#else
assert( pCtx->pVdbe!=0 );
#endif
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
} }
@ -735,6 +751,11 @@ void sqlite3_set_auxdata(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( iArg<0 ) goto failed; if( iArg<0 ) goto failed;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( pVdbe==0 ) goto failed;
#else
assert( pVdbe!=0 );
#endif
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;

View File

@ -1090,7 +1090,7 @@ struct ValueNewStat4Ctx {
** Otherwise, if the second argument is non-zero, then this function is ** Otherwise, if the second argument is non-zero, then this function is
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that ** already been allocated, allocate the UnpackedRecord structure that
** that function will return to its caller here. Then return a pointer ** that function will return to its caller here. Then return a pointer to
** an sqlite3_value within the UnpackedRecord.a[] array. ** an sqlite3_value within the UnpackedRecord.a[] array.
*/ */
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
@ -1134,6 +1134,111 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
return sqlite3ValueNew(db); 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, and
** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
**
** 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 = 0; /* Function arguments */
int i; /* Iterator variable */
assert( pCtx!=0 );
assert( (p->flags & EP_TokenOnly)==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 || rc!=SQLITE_OK ) goto value_from_function_out;
}
}
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));
pCtx->pParse->rc = rc;
}else{
sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
rc = sqlite3VdbeChangeEncoding(pVal, enc);
if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
rc = SQLITE_TOOBIG;
}
}
value_from_function_out:
if( rc!=SQLITE_OK ){
pVal = 0;
}
if( apVal ){
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 ** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object ** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
@ -1166,6 +1271,12 @@ static int valueFromExpr(
while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft; while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
/* Compressed expressions only appear when parsing the DEFAULT clause
** on a table column definition, and hence only when pCtx==0. This
** check ensures that an EP_TokenOnly expression is never passed down
** into valueFromFunction(). */
assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 );
if( op==TK_CAST ){ if( op==TK_CAST ){
u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
@ -1242,6 +1353,10 @@ static int valueFromExpr(
} }
#endif #endif
else if( op==TK_FUNCTION && pCtx!=0 ){
rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
}
*ppVal = pVal; *ppVal = pVal;
return rc; return rc;

78
test/analyzeF.test Normal file
View File

@ -0,0 +1,78 @@
# 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