]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Allow the IN operator to take a list of arbitrary expressions on its
authordrh <drh@noemail.net>
Fri, 8 Jul 2005 18:25:26 +0000 (18:25 +0000)
committerdrh <drh@noemail.net>
Fri, 8 Jul 2005 18:25:26 +0000 (18:25 +0000)
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

manifest
manifest.uuid
src/expr.c
test/in.test

index 218ec3dcf8ae8e0f42d6adbbd7829b6704852303..0aa75fa69cc72dd19fe2dab80ff6d1ec385ebe0c 100644 (file)
--- 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
index 9b1de654ac449a1ff074636845eccb5e744130a5..59f3e90f899b138a88e3d2804748eeac132f36bd 100644 (file)
@@ -1 +1 @@
-3bb9ce5f20d0a6bc19df31df9b8e82044c3e6004
\ No newline at end of file
+ba56478dd8bc2135749966ff55831fd497883781
\ No newline at end of file
index 2303a7a16af08931343609d8dc3c1b69cae1985d..33bb8023768eaa0639de7a0169ce70a7fe030f9e 100644 (file)
@@ -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 <ctype.h>
@@ -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(<exprlist>)'
-      ** 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 <exprlist>.
       **
@@ -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 <exprlist>. */
-        for(i=0; i<pExpr->pList->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;
 }
index db6c7add7aa822d8279e7b56483f06679d612cf6..37d8792c7b41ac6be1bbfbf6bc0b6606ec58dbc6 100644 (file)
@@ -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