From: drh Date: Tue, 17 Aug 2010 23:13:41 +0000 (+0000) Subject: Cherrypick the changes for enhancement requests [e090183531fc27474] X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ab72fadb457648f4452f2cfe5da8b8fb9e7892d4;p=thirdparty%2Fsqlite.git Cherrypick the changes for enhancement requests [e090183531fc27474] (use indices on LIKE with no wildcards) and [4711020446da7d93d993] (use nocase index for LIKE even if the column is binary) into the 3.6.23.1 release of the Apple-OSX branch. FossilOrigin-Name: 220cca50da08c5166afa3d2364fdf7f8e7308836 --- diff --git a/manifest b/manifest index eaa5aa7a3b..09ff4bd590 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C Merge\sin\schanges\sup\sto\sand\sincluding\sthe\s3.6.23.1\srelease. -D 2010-06-16T19:48:57 +C Cherrypick\sthe\schanges\sfor\senhancement\srequests\s[e090183531fc27474]\s\n(use\sindices\son\sLIKE\swith\sno\swildcards)\sand\s[4711020446da7d93d993]\n(use\snocase\sindex\sfor\sLIKE\seven\sif\sthe\scolumn\sis\sbinary)\sinto\sthe\n3.6.23.1\srelease\sof\sthe\sApple-OSX\sbranch. +D 2010-08-17T23:13:42 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in b12be4429b75eca982a5646752652efde58e8f29 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -124,7 +124,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c ceb247eb31620bba66a94c3f697db489a1652353 F src/date.c 485a4409a384310e6d93fd1104a9d0a8658becd9 F src/delete.c 610dc008e88a9599f905f5cbe9577ac9c36e0581 -F src/expr.c 6baed2a0448d494233d9c0a610eea018ab386a32 +F src/expr.c 6bb1f6a7213061c325b679c3aa0aa2358094ad7f F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0 F src/func.c cc68e721c25b9ad0d5c2d9e173298cfc1818fe4c @@ -160,7 +160,7 @@ F src/os_unix.c fdeb37c703243141470396acf32331674b905e55 F src/os_win.c bc65553f911439a6b1aa3cf22f34e5ea1c4aa394 F src/pager.c e39ac887694a6644135f5e4151fe293b5397dd64 F src/pager.h 1b32faf2e578ac3e7bcf9c9d11217128261c5c54 -F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e +F src/parse.y 07fdc757efdb43bac77120f3b50db15d5fe7f5db F src/pcache.c 4956b41d6ba913f7a8a56fbf32be78caed0e45c2 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache1.c 2bb2261190b42a348038f5b1c285c8cef415fcc8 @@ -174,7 +174,7 @@ F src/select.c 4113ef360430ed4e7533690ef46d06c20204adce F src/shell.c c40427c7245535a04a9cb4a417b6cc05c022e6a4 F src/sqlite.h.in f9a9be1bce911669a259f7c747bf05635cb360b5 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 -F src/sqliteInt.h 6873f7f4c24fcdceece8777f2a1cbec049df77a0 +F src/sqliteInt.h 4ac68f515068deb0435b8e4de46844368e95018a F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6 F src/status.c d329385a2cba3ea49d9d68af0ad84b22d46b4f40 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -227,7 +227,7 @@ F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c 606adf51cd6d4ba51a8c6dccede06a6f7b0dd72d F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 399ea4c090284c9d16f76d685b9b44e8b9b4442b +F src/where.c 0777e1f8f1cd88ce37da41d6bbd54b8307705ee4 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45 @@ -238,7 +238,7 @@ F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc F test/analyze.test ad5329098fe4de4a96852231d53e3e9e6283ad4b F test/analyze2.test a2ad7b0a4e13801ee3968fe70f22aff52326569c -F test/analyze3.test 506203875258ffd8ffa879b9c3c5432022d2b6d8 +F test/analyze3.test 535bf0762f49fa96885efe8568738276c2204a2a F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6 F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e @@ -468,7 +468,7 @@ F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710 F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test 4b594af9eddfd01018df1e9b1d18721aff619fa7 +F test/like.test 565d240313f15a8afa8d7098dc9fe303c1e2a496 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0 @@ -799,14 +799,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 5c0afe70a5ee2b378896bf30426823dc5ae4e95c 776679af588625f13307369770979bccae7cf03a -R 90e27fcea4f7f54474c3a0fb8671dd73 +P 21ca87f69125a9e7124c6ddc566d17f64661b0d3 +R 746b72865ced8034924c2cc1c718a49c U drh -Z b8746f44feb03a04fe1e2272410b2363 +Z bb87ab062eae07f981b513eb1b914158 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFMGSqsoxKgR168RlERAtaeAJwOjCShd/QM6A+bZt7Sd1NRZQnhYgCdEZRm -OPl6AbsNdGPQiQAPLtVWZiQ= -=hX2q +iD8DBQFMaxeqoxKgR168RlERAsD4AJ9c9h3cETIYGap5CjJMrATUO3T+cACgjLkN +T2aAsvx2yasC+G+Gv6NOb3E= +=s+Bg -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index c09111da59..0c2661ac38 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -21ca87f69125a9e7124c6ddc566d17f64661b0d3 \ No newline at end of file +220cca50da08c5166afa3d2364fdf7f8e7308836 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 034088fafc..97a589b557 100644 --- a/src/expr.c +++ b/src/expr.c @@ -55,6 +55,18 @@ char sqlite3ExprAffinity(Expr *pExpr){ return pExpr->affinity; } +/* +** Set the explicit collating sequence for an expression to the +** collating sequence supplied in the second argument. +*/ +Expr *sqlite3ExprSetColl(Expr *pExpr, CollSeq *pColl){ + if( pExpr && pColl ){ + pExpr->pColl = pColl; + pExpr->flags |= EP_ExpCollate; + } + return pExpr; +} + /* ** Set the collating sequence for expression pExpr to be the collating ** sequence named by pToken. Return a pointer to the revised expression. @@ -62,18 +74,13 @@ char sqlite3ExprAffinity(Expr *pExpr){ ** flag. An explicit collating sequence will override implicit ** collating sequences. */ -Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pCollName){ +Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr *pExpr, Token *pCollName){ char *zColl = 0; /* Dequoted name of collation sequence */ CollSeq *pColl; sqlite3 *db = pParse->db; zColl = sqlite3NameFromToken(db, pCollName); - if( pExpr && zColl ){ - pColl = sqlite3LocateCollSeq(pParse, zColl); - if( pColl ){ - pExpr->pColl = pColl; - pExpr->flags |= EP_ExpCollate; - } - } + pColl = sqlite3LocateCollSeq(pParse, zColl); + sqlite3ExprSetColl(pExpr, pColl); sqlite3DbFree(db, zColl); return pExpr; } diff --git a/src/parse.y b/src/parse.y index 98714ee343..deac2a214c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -780,7 +780,7 @@ expr(A) ::= VARIABLE(X). { spanSet(&A, &X, &X); } expr(A) ::= expr(E) COLLATE ids(C). { - A.pExpr = sqlite3ExprSetColl(pParse, E.pExpr, &C); + A.pExpr = sqlite3ExprSetCollByToken(pParse, E.pExpr, &C); A.zStart = E.zStart; A.zEnd = &C.z[C.n]; } @@ -1091,7 +1091,7 @@ idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). { Expr *p = 0; if( C.n>0 ){ p = sqlite3Expr(pParse->db, TK_COLUMN, 0); - sqlite3ExprSetColl(pParse, p, &C); + sqlite3ExprSetCollByToken(pParse, p, &C); } A = sqlite3ExprListAppend(pParse,X, p); sqlite3ExprListSetName(pParse,A,&Y,1); @@ -1102,7 +1102,7 @@ idxlist(A) ::= nm(Y) collate(C) sortorder(Z). { Expr *p = 0; if( C.n>0 ){ p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); - sqlite3ExprSetColl(pParse, p, &C); + sqlite3ExprSetCollByToken(pParse, p, &C); } A = sqlite3ExprListAppend(pParse,0, p); sqlite3ExprListSetName(pParse, A, &Y, 1); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5720b9cf5c..5b718e26b2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2847,7 +2847,8 @@ int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *); +Expr *sqlite3ExprSetColl(Expr*, CollSeq*); +Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3CheckObjectName(Parse *, const char *); void sqlite3VdbeSetChanges(sqlite3 *, int); diff --git a/src/where.c b/src/where.c index 5f81ce0768..d52b1dbf1d 100644 --- a/src/where.c +++ b/src/where.c @@ -633,7 +633,6 @@ static int isLikeOrGlob( 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 */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ @@ -652,19 +651,6 @@ static int isLikeOrGlob( return 0; } assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */ - pColl = sqlite3ExprCollSeq(pParse, pLeft); - if( pColl==0 ) return 0; /* Happens when LHS has an undefined collation */ - if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) && - (pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){ - /* IMP: R-09003-32046 For the GLOB operator, the column must use the - ** default BINARY collating sequence. - ** IMP: R-41408-28306 For the LIKE operator, if case_sensitive_like mode - ** is enabled then the column must use the default BINARY collating - ** sequence, or if case_sensitive_like mode is disabled then the column - ** must use the built-in NOCASE collating sequence. - */ - return 0; - } pRight = pList->a[0].pExpr; op = pRight->op; @@ -687,9 +673,9 @@ static int isLikeOrGlob( while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; } - if( cnt!=0 && c!=0 && 255!=(u8)z[cnt-1] ){ + if( cnt!=0 && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; - *pisComplete = z[cnt]==wc[0] && z[cnt+1]==0; + *pisComplete = c==wc[0] && z[cnt+1]==0; pPrefix = sqlite3Expr(db, TK_STRING, z); if( pPrefix ) pPrefix->u.zToken[cnt] = 0; *ppPrefix = pPrefix; @@ -1244,6 +1230,7 @@ static void exprAnalyze( Expr *pNewExpr2; int idxNew1; int idxNew2; + CollSeq *pColl; /* Collating sequence to use */ pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); @@ -1264,11 +1251,16 @@ static void exprAnalyze( } *pC = c + 1; } - pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0); + pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, noCase ? "NOCASE" : "BINARY",0); + pNewExpr1 = sqlite3PExpr(pParse, TK_GE, + sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl), + pStr1, 0); idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew1==0 ); exprAnalyze(pSrc, pWC, idxNew1); - pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0); + pNewExpr2 = sqlite3PExpr(pParse, TK_LT, + sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl), + pStr2, 0); idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew2); diff --git a/test/analyze3.test b/test/analyze3.test index 438ecd7b2b..6fc70d99c5 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -268,6 +268,22 @@ do_test analyze3-2.5 { set like "%a" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } } {999 999 100} +do_test analyze3-2.6 { + set like "a" + sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } +} {101 0 0} +do_test analyze3-2.7 { + set like "ab" + sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } +} {11 0 0} +do_test analyze3-2.8 { + set like "abc" + sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } +} {2 0 1} +do_test analyze3-2.9 { + set like "a_c" + sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } +} {101 0 10} #------------------------------------------------------------------------- diff --git a/test/like.test b/test/like.test index a2de6866b5..229f386880 100644 --- a/test/like.test +++ b/test/like.test @@ -194,6 +194,31 @@ do_test like-3.4 { set sqlite_like_count } 0 +# The LIKE optimization still works when the RHS is a string with no +# wildcard. Ticket [e090183531fc2747] +# +do_test like-3.4.2 { + queryplan { + SELECT x FROM t1 WHERE x LIKE 'a' ORDER BY 1; + } +} {a nosort {} i1} +do_test like-3.4.3 { + queryplan { + SELECT x FROM t1 WHERE x LIKE 'ab' ORDER BY 1; + } +} {ab nosort {} i1} +do_test like-3.4.4 { + queryplan { + SELECT x FROM t1 WHERE x LIKE 'abcd' ORDER BY 1; + } +} {abcd nosort {} i1} +do_test like-3.4.5 { + queryplan { + SELECT x FROM t1 WHERE x LIKE 'abcde' ORDER BY 1; + } +} {nosort {} i1} + + # Partial optimization when the pattern does not end in '%' # do_test like-3.5 { @@ -309,6 +334,26 @@ do_test like-3.24 { set sqlite_like_count } 6 +# GLOB optimization when there is no wildcard. Ticket [e090183531fc2747] +# +do_test like-3.25 { + queryplan { + SELECT x FROM t1 WHERE x GLOB 'a' ORDER BY 1; + } +} {a nosort {} i1} +do_test like-3.26 { + queryplan { + SELECT x FROM t1 WHERE x GLOB 'abcd' ORDER BY 1; + } +} {abcd nosort {} i1} +do_test like-3.27 { + queryplan { + SELECT x FROM t1 WHERE x GLOB 'abcde' ORDER BY 1; + } +} {nosort {} i1} + + + # No optimization if the LHS of the LIKE is not a column name or # if the RHS is not a string. # @@ -733,5 +778,94 @@ do_test like-10.15 { } } {12 123 scan 5 like 6} +# LIKE and GLOB where the default collating sequence is not appropriate +# but an index with the appropriate collating sequence exists. +# +do_test like-11.0 { + execsql { + CREATE TABLE t11( + a INTEGER PRIMARY KEY, + b TEXT COLLATE nocase, + c TEXT COLLATE binary + ); + INSERT INTO t11 VALUES(1, 'a','a'); + INSERT INTO t11 VALUES(2, 'ab','ab'); + INSERT INTO t11 VALUES(3, 'abc','abc'); + INSERT INTO t11 VALUES(4, 'abcd','abcd'); + INSERT INTO t11 VALUES(5, 'A','A'); + INSERT INTO t11 VALUES(6, 'AB','AB'); + INSERT INTO t11 VALUES(7, 'ABC','ABC'); + INSERT INTO t11 VALUES(8, 'ABCD','ABCD'); + INSERT INTO t11 VALUES(9, 'x','x'); + INSERT INTO t11 VALUES(10, 'yz','yz'); + INSERT INTO t11 VALUES(11, 'X','X'); + INSERT INTO t11 VALUES(12, 'YZ','YZ'); + SELECT count(*) FROM t11; + } +} {12} +do_test like-11.1 { + queryplan { + PRAGMA case_sensitive_like=OFF; + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd ABC ABCD nosort t11 *} +do_test like-11.2 { + queryplan { + PRAGMA case_sensitive_like=ON; + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd nosort t11 *} +do_test like-11.3 { + queryplan { + PRAGMA case_sensitive_like=OFF; + CREATE INDEX t11b ON t11(b); + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd ABC ABCD sort {} t11b} +do_test like-11.4 { + queryplan { + PRAGMA case_sensitive_like=ON; + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd nosort t11 *} +do_test like-11.5 { + queryplan { + PRAGMA case_sensitive_like=OFF; + DROP INDEX t11b; + CREATE INDEX t11bnc ON t11(b COLLATE nocase); + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd ABC ABCD sort {} t11bnc} +do_test like-11.6 { + queryplan { + CREATE INDEX t11bb ON t11(b COLLATE binary); + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd ABC ABCD sort {} t11bnc} +do_test like-11.7 { + queryplan { + PRAGMA case_sensitive_like=ON; + SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a; + } +} {abc abcd sort {} t11bb} +do_test like-11.8 { + queryplan { + PRAGMA case_sensitive_like=OFF; + SELECT b FROM t11 WHERE b GLOB 'abc*' ORDER BY a; + } +} {abc abcd sort {} t11bb} +do_test like-11.9 { + queryplan { + CREATE INDEX t11cnc ON t11(c COLLATE nocase); + CREATE INDEX t11cb ON t11(c COLLATE binary); + SELECT c FROM t11 WHERE c LIKE 'abc%' ORDER BY a; + } +} {abc abcd ABC ABCD sort {} t11cnc} +do_test like-11.10 { + queryplan { + SELECT c FROM t11 WHERE c GLOB 'abc*' ORDER BY a; + } +} {abc abcd sort {} t11cb} + finish_test