aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2010-12-06 21:06:09 +0000
committerdrh <drh@noemail.net>2010-12-06 21:06:09 +0000
commitf58ee7f1aa1ef87d2c493af096fa8ac72d762cf0 (patch)
treea689363e01fadad2e79844a7bb1bb19ad6046776 /src
parentef4c0598438b409cc7367e7583a3aa01c16b3e3f (diff)
downloadsqlite-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.c12
-rw-r--r--src/sqliteInt.h1
-rw-r--r--src/test1.c59
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 */