From: drh Date: Fri, 8 Jul 2005 18:25:26 +0000 (+0000) Subject: Allow the IN operator to take a list of arbitrary expressions on its X-Git-Tag: version-3.6.10~3617 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=57dbd7b324375c368551a6d891b7a7acc87d9398;p=thirdparty%2Fsqlite.git Allow the IN operator to take a list of arbitrary expressions on its right-hand side. The expressions no longer need to be constant. The current implementation seems to work but needs more testing and optimization. (CVS 2542) FossilOrigin-Name: ba56478dd8bc2135749966ff55831fd497883781 --- diff --git a/manifest b/manifest index 218ec3dcf8..0aa75fa69c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sname\sof\sthe\sOpenTemp\sopcode\sto\sOpenVirtual\swhich\sis\smore\ndescriptive\sof\swhat\sit\sdoes.\s(CVS\s2541) -D 2005-07-08T17:13:47 +C Allow\sthe\sIN\soperator\sto\stake\sa\slist\sof\sarbitrary\sexpressions\son\sits\nright-hand\sside.\s\sThe\sexpressions\sno\slonger\sneed\sto\sbe\sconstant.\s\sThe\ncurrent\simplementation\sseems\sto\swork\sbut\sneeds\smore\stesting\sand\soptimization.\s(CVS\s2542) +D 2005-07-08T18:25:26 F Makefile.in 3c10cd7bc3ecbd60fe4d5a5c0f59bfa7fb217a66 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -38,7 +38,7 @@ F src/callback.c 0910b611e0c158f107ee3ff86f8a371654971e2b F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940 F src/delete.c 250d436a68fe371b4ab403d1c0f6fdc9a6860c39 F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d -F src/expr.c daf3515d33467090741d98227577356c108ea33f +F src/expr.c 94dce12d5228af02fdafc23e56abfeae25f3b694 F src/func.c e6637354fe3a66dfac063a49109f277cde9ce87d F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 @@ -137,7 +137,7 @@ F test/expr.test 648f733f9d9aa9db82de59e69d1322b8b52f701a F test/fkey1.test 81bb13caaa78f58d7d191d7f535529f7c91d821a F test/func.test b062105b45cf8fb5b386ba137180c0f439eea0c9 F test/hook.test f8605cde4c77b2c6a4a73723bf6c507796a64dda -F test/in.test ed134f8d477a6280297ced1646de83cccf8f196d +F test/in.test cead6165aebbe0d451bb2263a307173acfeb6240 F test/index.test 51e01a0928b4b61228917ddd8c6c0e2466547f6f F test/index2.test 9ad98243fd7fe833795a9cc662f371f0eed4ff4f F test/index3.test 72bd07b508022db688ec536c460345d24a3912e3 @@ -285,7 +285,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P f4a66ed04dfd8714746b766b4859682ea18e328f -R 7dbd5cf11e082700c07694668805a635 +P 3bb9ce5f20d0a6bc19df31df9b8e82044c3e6004 +R 1efa9cdd449acebde300ce2385775e19 U drh -Z 2074933014582e5567aec0bab96430cb +Z 5c326e79427e109a129a76bef3edf05e diff --git a/manifest.uuid b/manifest.uuid index 9b1de654ac..59f3e90f89 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3bb9ce5f20d0a6bc19df31df9b8e82044c3e6004 \ No newline at end of file +ba56478dd8bc2135749966ff55831fd497883781 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 2303a7a16a..33bb802376 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.210 2005/07/08 17:13:47 drh Exp $ +** $Id: expr.c,v 1.211 2005/07/08 18:25:26 drh Exp $ */ #include "sqliteInt.h" #include @@ -1238,19 +1238,25 @@ struct QueryCoder { */ #ifndef SQLITE_OMIT_SUBQUERY void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ - int label = 0; /* Address after sub-select code */ + int testAddr = 0; /* One-time test address */ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; - /* If this is not a variable (correlated) select, then execute - ** it only once. Unless this is part of a trigger program. In - ** that case re-execute every time (this could be optimized). + /* This code must be run in its entirety every time it is encountered + ** if any of the following is true: + ** + ** * The right-hand side is a correlated subquery + ** * The right-hand side is an expression list containing variables + ** * We are inside a trigger + ** + ** If all of the above are false, then we can run this code just once + ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); - label = sqlite3VdbeMakeLabel(v); - sqlite3VdbeAddOp(v, OP_If, 0, label); + testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); + assert( testAddr>0 ); sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3VdbeAddOp(v, OP_MemStore, mem, 1); } @@ -1268,7 +1274,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ affinity = sqlite3ExprAffinity(pExpr->pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' - ** expression it is handled the same way. A temporary table is + ** expression it is handled the same way. A virtual table is ** filled with single-field index keys representing the results ** from the SELECT or the . ** @@ -1310,20 +1316,30 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ ** a column, use numeric affinity. */ int i; + ExprList *pList = pExpr->pList; + struct ExprList_item *pItem; + if( !affinity ){ affinity = SQLITE_AFF_NUMERIC; } keyInfo.aColl[0] = pExpr->pLeft->pColl; /* Loop through each expression in . */ - for(i=0; ipList->nExpr; i++){ - Expr *pE2 = pExpr->pList->a[i].pExpr; - - /* Check that the expression is constant and valid. */ - if( !sqlite3ExprIsConstant(pE2) ){ - sqlite3ErrorMsg(pParse, - "right-hand side of IN operator must be constant"); - return; + for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ + Expr *pE2 = pItem->pExpr; + + /* If the expression is not constant then we will need to + ** disable the test that was generated above that makes sure + ** this code only executes once. Because for a non-constant + ** expression we need to rerun this code each time. + */ + if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ + VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1); + int i; + for(i=0; i<4; i++){ + aOp[i].opcode = OP_Noop; + } + testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ @@ -1364,8 +1380,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ if( pExpr->pSelect ){ sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0); } - if( label<0 ){ - sqlite3VdbeResolveLabel(v, label); + if( testAddr ){ + sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v)); } return; } diff --git a/test/in.test b/test/in.test index db6c7add7a..37d8792c7b 100644 --- a/test/in.test +++ b/test/in.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the IN and BETWEEN operator. # -# $Id: in.test,v 1.13 2005/01/21 03:12:16 danielk1977 Exp $ +# $Id: in.test,v 1.14 2005/07/08 18:25:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -81,24 +81,20 @@ do_test in-2.5 { } {1 2 103 104 5 6 7 8 9 10} do_test in-2.6 { - set v [catch {execsql {SELECT a FROM t1 WHERE b IN (b+10,20)}} msg] - lappend v $msg -} {1 {right-hand side of IN operator must be constant}} + execsql {SELECT a FROM t1 WHERE b IN (b+8,64)} +} {6} do_test in-2.7 { - set v [catch {execsql {SELECT a FROM t1 WHERE b IN (max(5,10,b),20)}} msg] - lappend v $msg -} {1 {right-hand side of IN operator must be constant}} + execsql {SELECT a FROM t1 WHERE b IN (max(5,10,b),20)} +} {4 5 6 7 8 9 10} do_test in-2.8 { execsql {SELECT a FROM t1 WHERE b IN (8*2,64/2) ORDER BY b} } {4 5} do_test in-2.9 { - set v [catch {execsql {SELECT a FROM t1 WHERE b IN (max(5,10),20)}} msg] - lappend v $msg -} {1 {right-hand side of IN operator must be constant}} + execsql {SELECT a FROM t1 WHERE b IN (max(5,10),20)} +} {} do_test in-2.10 { - set v [catch {execsql {SELECT a FROM t1 WHERE min(0,b IN (a,30))}} msg] - lappend v $msg -} {1 {right-hand side of IN operator must be constant}} + execsql {SELECT a FROM t1 WHERE min(0,b IN (a,30))} +} {} do_test in-2.11 { set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} msg] lappend v $msg