]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a bug in the LIKE query optimization. (Found by coverage testing.) (CVS 6137)
authordrh <drh@noemail.net>
Wed, 7 Jan 2009 18:24:03 +0000 (18:24 +0000)
committerdrh <drh@noemail.net>
Wed, 7 Jan 2009 18:24:03 +0000 (18:24 +0000)
FossilOrigin-Name: fe90e9116b6e1e25cf3119d2777a8e9c135153ce

manifest
manifest.uuid
src/test1.c
src/where.c
test/like.test

index 3390a59fd597961db8d8a69e12ec81f9f44ddd6b..197b00fb3f142aa43ba17aaddc60098ea488405e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\sthe\ssame\schange\sas\s(6121)\s(accidentally\sreverted).\sAlso\senhance\stest_journal.c\sto\scatch\sthis\skind\sof\sbug.\s(CVS\s6136)
-D 2009-01-07T18:08:49
+C Fix\sa\sbug\sin\sthe\sLIKE\squery\soptimization.\s\s(Found\sby\scoverage\stesting.)\s(CVS\s6137)
+D 2009-01-07T18:24:03
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 05461a9b5803d5ad10c79f989801e9fd2cc3e592
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -163,7 +163,7 @@ F src/sqliteLimit.h 651a2757ba55aeba1da167786b6a8c3404433940
 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
 F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
 F src/tclsqlite.c 4415e1033bd3e92b05a6a9cde911ee4de3b82df9
-F src/test1.c b193b8b80617bdb8297b25a87d00ee8d5a125d0d
+F src/test1.c 058a52226e6c47e92b9df14654c5a1b41009e0fe
 F src/test2.c 724095fc69cb54b018aaa4463a56836c0b53a17a
 F src/test3.c 88a246b56b824275300e6c899634fbac1dc94b14
 F src/test4.c f79ab52d27ff49b784b631a42e2ccd52cfd5c84c
@@ -207,7 +207,7 @@ F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
 F src/vdbemem.c 19f94b504d3da44b31aef200fa6c8e07862de2e8
 F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
 F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
-F src/where.c ad9d49f77b9c70adc38cf1b829c870f30a9afe04
+F src/where.c 9852acecfeee1f8650fdec46f20e2368e6c159a0
 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
@@ -415,7 +415,7 @@ F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
 F test/jrnlmode.test 513b495624bfe54da24ae1208125421d8167953d
 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
-F test/like.test fef924922828d5a2a5bff80b9bdd9ff57a1ca500
+F test/like.test e55cbbc21729f577b74ec333c753a2d6eda03f9f
 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
 F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e
 F test/loadext.test 18db29c081380fdedcfbd8c633847712059ae104
@@ -693,7 +693,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 0f57011e3b21fa5f6a819ce5a7fd8d44ea70679f
-R cebd5b9f713ddcff8e7a2c71139b4a4c
-U danielk1977
-Z 62d24e33d87117ee5ab38c9511e98dd8
+P ccc9c211a285fd4da68b69e15594f080371be522
+R 3780da89c170554b5cb3d38edab02288
+U drh
+Z 9ba15e241fcdcbb40439174ae087420f
index 441b07d88b794703f5009cd52476f6c3fd2a8308..0da10d38c027d3a5ac4a74e44d31e35d6d09fef6 100644 (file)
@@ -1 +1 @@
-ccc9c211a285fd4da68b69e15594f080371be522
\ No newline at end of file
+fe90e9116b6e1e25cf3119d2777a8e9c135153ce
\ No newline at end of file
index d73dec9367ac011d4cb32b9fc2eaeb131edb63af..3dfc715af52e2ee51e641f5618386cf01e143e17 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.338 2008/12/17 15:18:18 danielk1977 Exp $
+** $Id: test1.c,v 1.339 2009/01/07 18:24:03 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -333,6 +333,53 @@ static int test_exec_printf(
   return TCL_OK;
 }
 
+/*
+** Usage:  sqlite3_exec_hex  DB  HEX
+**
+** Invoke the sqlite3_exec() on a string that is obtained by translating
+** HEX into ASCII.  Most characters are translated as is.  %HH becomes
+** a hex character.
+*/
+static int test_exec_hex(
+  void *NotUsed,
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int argc,              /* Number of arguments */
+  char **argv            /* Text of each argument */
+){
+  sqlite3 *db;
+  Tcl_DString str;
+  int rc, i, j;
+  char *zErr = 0;
+  char *zHex;
+  char zSql[500];
+  char zBuf[30];
+  if( argc!=3 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
+       " DB HEX", 0);
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+  zHex = argv[2];
+  for(i=j=0; i<sizeof(zSql) && zHex[j]; i++, j++){
+    if( zHex[j]=='%' && zHex[j+2] && zHex[j+2] ){
+      zSql[i] = (testHexToInt(zHex[j+1])<<4) + testHexToInt(zHex[j+2]);
+      j += 2;
+    }else{
+      zSql[i] = zHex[j];
+    }
+  }
+  zSql[i] = 0;
+  Tcl_DStringInit(&str);
+  rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
+  sprintf(zBuf, "%d", rc);
+  Tcl_AppendElement(interp, zBuf);
+  Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
+  Tcl_DStringFree(&str);
+  if( zErr ) sqlite3_free(zErr);
+  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+  return TCL_OK;
+}
+
 /*
 ** Usage:  db_enter DB
 **         db_leave DB
@@ -4758,6 +4805,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "sqlite3_snprintf_int",          (Tcl_CmdProc*)test_snprintf_int     },
      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
+     { "sqlite3_exec_hex",              (Tcl_CmdProc*)test_exec_hex         },
      { "sqlite3_exec",                  (Tcl_CmdProc*)test_exec             },
      { "sqlite3_exec_nr",               (Tcl_CmdProc*)test_exec_nr          },
 #ifndef SQLITE_OMIT_GET_TABLE
index ca513be0623efc072af5f4b8f53b31459fc23d4d..451dce9cb99b9962600b76ebf2e41c45906a661c 100644 (file)
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.357 2009/01/06 14:19:37 drh Exp $
+** $Id: where.c,v 1.358 2009/01/07 18:24:03 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -264,20 +264,16 @@ static void whereClauseClear(WhereClause*);
 ** Deallocate all memory associated with a WhereOrInfo object.
 */
 static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){
-  if( p ){
-    whereClauseClear(&p->wc);
-    sqlite3DbFree(db, p);
-  }
+  whereClauseClear(&p->wc);
+  sqlite3DbFree(db, p);
 }
 
 /*
 ** Deallocate all memory associated with a WhereAndInfo object.
 */
 static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){
-  if( p ){
-    whereClauseClear(&p->wc);
-    sqlite3DbFree(db, p);
-  }
+  whereClauseClear(&p->wc);
+  sqlite3DbFree(db, p);
 }
 
 /*
@@ -623,13 +619,14 @@ static int isLikeOrGlob(
   int *pisComplete, /* True if the only wildcard is % in the last character */
   int *pnoCase      /* True if uppercase is equivalent to lowercase */
 ){
-  const char *z;
-  Expr *pRight, *pLeft;
-  ExprList *pList;
-  int c, cnt;
-  char wc[3];
-  CollSeq *pColl;
-  sqlite3 *db = pParse->db;
+  const char *z;             /* String on RHS of LIKE operator */
+  Expr *pRight, *pLeft;      /* Right and left size of LIKE operator */
+  ExprList *pList;           /* List of operands to the LIKE operator */
+  int c;                     /* One character in z[] */
+  int cnt;                   /* Number of non-wildcard prefix characters */
+  char wc[3];                /* Wildcard characters */
+  CollSeq *pColl;            /* Collating sequence for LHS */
+  sqlite3 *db = pParse->db;  /* Database connection */
 
   if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
     return 0;
@@ -639,8 +636,7 @@ static int isLikeOrGlob(
 #endif
   pList = pExpr->pList;
   pRight = pList->a[0].pExpr;
-  if( pRight->op!=TK_STRING
-   && (pRight->op!=TK_REGISTER || pRight->iColumn!=TK_STRING) ){
+  if( pRight->op!=TK_STRING ){
     return 0;
   }
   pLeft = pList->a[1].pExpr;
@@ -663,7 +659,7 @@ static int isLikeOrGlob(
   if( z ){
     while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; }
   }
-  if( cnt==0 || 255==(u8)z[cnt] ){
+  if( cnt==0 || 255==(u8)z[cnt-1] ){
     return 0;
   }
   *pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
index 38951cb03ddce069c88a2fa45c504237fd6f9559..15d3c66aaf63376396fcc567323e25d45e76a519 100644 (file)
@@ -13,7 +13,7 @@
 # in particular the optimizations that occur to help those operators
 # run faster.
 #
-# $Id: like.test,v 1.10 2008/09/09 12:31:34 drh Exp $
+# $Id: like.test,v 1.11 2009/01/07 18:24:03 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -551,4 +551,72 @@ do_test like-8.4 {
 } {1 abcdef 1 ghijkl 1 mnopqr 2 abcdef 2 ghijkl 2 mnopqr}
 
 
+ifcapable like_opt {
+  # Evaluate SQL.  Return the result set followed by the
+  # and the number of full-scan steps.
+  #
+  db close
+  sqlite3 db test.db
+  proc count_steps {sql} {
+    set r [db eval $sql]
+    lappend r scan [db status step] sort [db status sort]
+  }
+  do_test like-9.1 {
+    count_steps {
+       SELECT x FROM t2 WHERE x LIKE 'x%'
+    }
+  } {xyz scan 0 sort 0}
+  do_test like-9.2 {
+    count_steps {
+       SELECT x FROM t2 WHERE x LIKE '_y%'
+    }
+  } {xyz scan 19 sort 0}
+  do_test like-9.3.1 {
+    set res [sqlite3_exec_hex db {
+       SELECT x FROM t2 WHERE x LIKE '%78%25'
+    }]
+  } {0 {x xyz}}
+  ifcapable explain {
+    do_test like-9.3.2 {
+      set res [sqlite3_exec_hex db {
+         EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%78%25'
+      }]
+      regexp {INDEX i2} $res
+    } {1}
+  }
+  do_test like-9.4.1 {
+    sqlite3_exec_hex db {INSERT INTO t2 VALUES('%ffhello')}
+    set res [sqlite3_exec_hex db {
+       SELECT substr(x,2) AS x FROM t2 WHERE +x LIKE '%ff%25'
+    }]
+  } {0 {x hello}}
+  do_test like-9.4.2 {
+    set res [sqlite3_exec_hex db {
+       SELECT substr(x,2) AS x FROM t2 WHERE x LIKE '%ff%25'
+    }]
+  } {0 {x hello}}
+  ifcapable explain {
+    do_test like-9.4.3 {
+      set res [sqlite3_exec_hex db {
+         EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%ff%25'
+      }]
+      regexp {INDEX i2} $res
+    } {0}
+  }
+  do_test like-9.5.1 {
+    set res [sqlite3_exec_hex db {
+       SELECT x FROM t2 WHERE x LIKE '%fe%25'
+    }]
+  } {0 {}}
+  ifcapable explain {
+    do_test like-9.5.2 {
+      set res [sqlite3_exec_hex db {
+         EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%fe%25'
+      }]
+      regexp {INDEX i2} $res
+    } {1}
+  }
+}
+
+
 finish_test