diff options
author | drh <drh@noemail.net> | 2010-12-06 21:06:09 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2010-12-06 21:06:09 +0000 |
commit | f58ee7f1aa1ef87d2c493af096fa8ac72d762cf0 (patch) | |
tree | a689363e01fadad2e79844a7bb1bb19ad6046776 /src | |
parent | ef4c0598438b409cc7367e7583a3aa01c16b3e3f (diff) | |
download | sqlite-f58ee7f1aa1ef87d2c493af096fa8ac72d762cf0.tar.gz sqlite-f58ee7f1aa1ef87d2c493af096fa8ac72d762cf0.zip |
Add the ability to disable constant factoring using sqlite3_test_control().
Add a TCL interface to this new capability and add tests cases to the TCL
test scripts to actually use the new capability.
FossilOrigin-Name: ad8bc68197f2b47435149c3dbc035f4e7210fc76
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 12 | ||||
-rw-r--r-- | src/sqliteInt.h | 1 | ||||
-rw-r--r-- | src/test1.c | 59 |
3 files changed, 72 insertions, 0 deletions
diff --git a/src/expr.c b/src/expr.c index 3a6ba9f3e..b902f451c 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3040,10 +3040,22 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){ ** Preevaluate constant subexpressions within pExpr and store the ** results in registers. Modify pExpr so that the constant subexpresions ** are TK_REGISTER opcodes that refer to the precomputed values. +** +** This routine is a no-op if the jump to the cookie-check code has +** already occur. Since the cookie-check jump is generated prior to +** any other serious processing, this check ensures that there is no +** way to accidently bypass the constant initializations. +** +** This routine is also a no-op if the SQLITE_FactorOutConst optimization +** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) +** interface. This allows test logic to verify that the same answer is +** obtained for queries regardless of whether or not constants are +** precomputed into registers or if they are inserted in-line. */ void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; if( pParse->cookieGoto ) return; + if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return; w.xExprCallback = evalConstExpr; w.xSelectCallback = 0; w.pParse = pParse; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6e8b768d5..4f0e08ea7 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -934,6 +934,7 @@ struct sqlite3 { #define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */ #define SQLITE_IndexCover 0x10 /* Disable index covering table */ #define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */ +#define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */ #define SQLITE_OptMask 0xff /* Mask of all disablable opts */ /* diff --git a/src/test1.c b/src/test1.c index 27834f36e..bab78451f 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5318,6 +5318,64 @@ static int test_print_eqp( #endif /* SQLITE_OMIT_EXPLAIN */ /* +** optimization_control DB OPT BOOLEAN +** +** Enable or disable query optimizations using the sqlite3_test_control() +** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. +** OPT is the name of the optimization to be disabled. +*/ +static int optimization_control( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int i; + sqlite3 *db; + const char *zOpt; + int onoff; + int mask; + static const struct { + const char *zOptName; + int mask; + } aOpt[] = { + { "all", SQLITE_OptMask }, + { "query-flattener", SQLITE_QueryFlattener }, + { "column-cache", SQLITE_ColumnCache }, + { "index-sort", SQLITE_IndexSort }, + { "index-search", SQLITE_IndexSearch }, + { "index-cover", SQLITE_IndexCover }, + { "groupby-order", SQLITE_GroupByOrder }, + { "factor-constants", SQLITE_FactorOutConst }, + }; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR; + zOpt = Tcl_GetString(objv[2]); + for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ + if( strcmp(zOpt, aOpt[i].zOptName)==0 ){ + mask = aOpt[i].mask; + break; + } + } + if( onoff ) mask = ~mask; + if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){ + Tcl_AppendResult(interp, "unknown optimization - should be one of:", + (char*)0); + for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ + Tcl_AppendResult(interp, " ", aOpt[i].zOptName); + } + return TCL_ERROR; + } + sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); + return TCL_OK; +} + +/* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ @@ -5434,6 +5492,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "save_prng_state", save_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, + { "optimization_control", optimization_control,0}, { "tcl_objproc", runAsObjProc, 0 }, /* sqlite3_column_*() API */ |