From d55e07296be575944439bdb621039eeedd89b17a Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 25 Oct 2012 03:07:29 +0000 Subject: [PATCH 01/10] Implementation of the INSTR() SQL function, as found in SQL Server, MySQL, and Oracle. FossilOrigin-Name: 49ccae964f3a8ae5aab87f56503121e09424545f --- manifest | 16 ++-- manifest.uuid | 2 +- src/func.c | 50 ++++++++++++ test/instr.test | 210 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 271 insertions(+), 7 deletions(-) create mode 100644 test/instr.test diff --git a/manifest b/manifest index 4e7f38b9c7..154f0ab25b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\ssubstructure\selements\shave\sproper\salignment\sin\sthe\sICU\stokenizers\nof\sFTS2\sand\sFTS3. -D 2012-10-19T02:10:53.511 +C Implementation\sof\sthe\sINSTR()\sSQL\sfunction,\sas\sfound\sin\sSQL\sServer,\sMySQL,\nand\sOracle. +D 2012-10-25T03:07:29.004 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -133,7 +133,7 @@ F src/delete.c e35684ad93c741266b086610d2efd709b7946853 F src/expr.c 57fb8e7a05d4147e40b9f4c439e37ed2abab9332 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c82a04e7a92bb728f9ab972b76590403283be2af -F src/func.c cbb90dc84b22eea25caf39528d342279e61b8898 +F src/func.c 1755cafdb8f2a291681f1ea55e0215518ebd6e52 F src/global.c fb44b11e02e06c995e6ed6642509edd23599d584 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 @@ -544,6 +544,7 @@ F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 F test/insert4.test 87f6798f31d60c4e177622fcc3663367e6ecbd90 F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 +F test/instr.test a34e1d46a9eefb098a7167ef0e730a4a3d82fba0 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 F test/intpkey.test 7af30f6ae852d8d1c2b70e4bf1551946742e92d8 @@ -1021,7 +1022,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9 -P 0482c73bfdf80b0c0ce9abea706554d7ddf36f69 -R 359b18ae3c286a09e1c7579425de96fe +P aaa2d9b0db74d8452d9294de17cff786ab4ec7c8 +R f112d1955e32a3fb5862640b210a6a2c +T *branch * instr +T *sym-instr * +T -sym-trunk * U drh -Z 09f8af841cfaabcfb0c92e8b07cb012e +Z 0dc399021047fb88f550870a282a864e diff --git a/manifest.uuid b/manifest.uuid index 9bcbd35ae6..e769b39548 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aaa2d9b0db74d8452d9294de17cff786ab4ec7c8 \ No newline at end of file +49ccae964f3a8ae5aab87f56503121e09424545f \ No newline at end of file diff --git a/src/func.c b/src/func.c index cc74a4ddda..c7af7d679c 100644 --- a/src/func.c +++ b/src/func.c @@ -168,6 +168,55 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ } } +/* +** Implementation of the instr() function. +** +** instr(haystack,needle) finds the first occurrence of needle +** in haystack and returns the number of previous characters plus 1, +** or 0 if needle does not occur within haystack. +** +** If both haystack and needle are BLOBs, then the result is one more than +** the number of bytes in haystack prior to the first occurrence of needle, +** or 0 if needle never occurs in haystack. +*/ +static void instrFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zHaystack; + const unsigned char *zNeedle; + int nHaystack; + int nNeedle; + int typeHaystack, typeNeedle; + int N = 1; + int isText; + + typeHaystack = sqlite3_value_type(argv[0]); + typeNeedle = sqlite3_value_type(argv[1]); + if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; + nHaystack = sqlite3_value_bytes(argv[0]); + nNeedle = sqlite3_value_bytes(argv[1]); + if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ + zHaystack = sqlite3_value_blob(argv[0]); + zNeedle = sqlite3_value_blob(argv[1]); + isText = 0; + }else{ + zHaystack = sqlite3_value_text(argv[0]); + zNeedle = sqlite3_value_text(argv[1]); + isText = 1; + } + while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ + N++; + do{ + nHaystack--; + zHaystack++; + }while( isText && (zHaystack[0]&0xc0)==0x80 ); + } + if( nNeedle>nHaystack ) N = 0; + sqlite3_result_int(context, N); +} + /* ** Implementation of the substr() function. ** @@ -1536,6 +1585,7 @@ void sqlite3RegisterGlobalFunctions(void){ AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), + FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), diff --git a/test/instr.test b/test/instr.test new file mode 100644 index 0000000000..b328cd1d2d --- /dev/null +++ b/test/instr.test @@ -0,0 +1,210 @@ +# 2012 October 24 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the built-in INSTR() functions. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Create a table to work with. +# +do_test instr-1.1 { + db eval {SELECT instr('abcdefg','a');} +} {1} +do_test instr-1.2 { + db eval {SELECT instr('abcdefg','b');} +} {2} +do_test instr-1.3 { + db eval {SELECT instr('abcdefg','c');} +} {3} +do_test instr-1.4 { + db eval {SELECT instr('abcdefg','d');} +} {4} +do_test instr-1.5 { + db eval {SELECT instr('abcdefg','e');} +} {5} +do_test instr-1.6 { + db eval {SELECT instr('abcdefg','f');} +} {6} +do_test instr-1.7 { + db eval {SELECT instr('abcdefg','g');} +} {7} +do_test instr-1.8 { + db eval {SELECT instr('abcdefg','h');} +} {0} +do_test instr-1.9 { + db eval {SELECT instr('abcdefg','abcdefg');} +} {1} +do_test instr-1.10 { + db eval {SELECT instr('abcdefg','abcdefgh');} +} {0} +do_test instr-1.11 { + db eval {SELECT instr('abcdefg','bcdefg');} +} {2} +do_test instr-1.12 { + db eval {SELECT instr('abcdefg','bcdefgh');} +} {0} +do_test instr-1.13 { + db eval {SELECT instr('abcdefg','cdefg');} +} {3} +do_test instr-1.14 { + db eval {SELECT instr('abcdefg','cdefgh');} +} {0} +do_test instr-1.15 { + db eval {SELECT instr('abcdefg','defg');} +} {4} +do_test instr-1.16 { + db eval {SELECT instr('abcdefg','defgh');} +} {0} +do_test instr-1.17 { + db eval {SELECT instr('abcdefg','efg');} +} {5} +do_test instr-1.18 { + db eval {SELECT instr('abcdefg','efgh');} +} {0} +do_test instr-1.19 { + db eval {SELECT instr('abcdefg','fg');} +} {6} +do_test instr-1.20 { + db eval {SELECT instr('abcdefg','fgh');} +} {0} +do_test instr-1.21 { + db eval {SELECT coalesce(instr('abcdefg',NULL),'nil');} +} {nil} +do_test instr-1.22 { + db eval {SELECT coalesce(instr(NULL,'x'),'nil');} +} {nil} +do_test instr-1.23 { + db eval {SELECT instr(12345,34);} +} {3} +do_test instr-1.24 { + db eval {SELECT instr(123456.78,34);} +} {3} +do_test instr-1.25 { + db eval {SELECT instr(123456.78,x'3334');} +} {3} +do_test instr-1.26 { + db eval {SELECT instr('äbcdefg','efg');} +} {5} +do_test instr-1.27 { + db eval {SELECT instr('€xyzzy','xyz');} +} {2} +do_test instr-1.28 { + db eval {SELECT instr('abc€xyzzy','xyz');} +} {5} +do_test instr-1.29 { + db eval {SELECT instr('abc€xyzzy','€xyz');} +} {4} +do_test instr-1.30 { + db eval {SELECT instr('abc€xyzzy','c€xyz');} +} {3} +do_test instr-1.31 { + db eval {SELECT instr(x'0102030405',x'01');} +} {1} +do_test instr-1.32 { + db eval {SELECT instr(x'0102030405',x'02');} +} {2} +do_test instr-1.33 { + db eval {SELECT instr(x'0102030405',x'03');} +} {3} +do_test instr-1.34 { + db eval {SELECT instr(x'0102030405',x'04');} +} {4} +do_test instr-1.35 { + db eval {SELECT instr(x'0102030405',x'05');} +} {5} +do_test instr-1.36 { + db eval {SELECT instr(x'0102030405',x'06');} +} {0} +do_test instr-1.37 { + db eval {SELECT instr(x'0102030405',x'0102030405');} +} {1} +do_test instr-1.38 { + db eval {SELECT instr(x'0102030405',x'02030405');} +} {2} +do_test instr-1.39 { + db eval {SELECT instr(x'0102030405',x'030405');} +} {3} +do_test instr-1.40 { + db eval {SELECT instr(x'0102030405',x'0405');} +} {4} +do_test instr-1.41 { + db eval {SELECT instr(x'0102030405',x'0506');} +} {0} +do_test instr-1.42 { + db eval {SELECT instr(x'0102030405',x'');} +} {1} +do_test instr-1.43 { + db eval {SELECT instr(x'',x'');} +} {1} +do_test instr-1.44 { + db eval {SELECT instr('','');} +} {1} +do_test instr-1.45 { + db eval {SELECT instr('abcdefg','');} +} {1} +unset -nocomplain longstr +set longstr abcdefghijklmonpqrstuvwxyz +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +append longstr $longstr +# puts [string length $longstr] +append longstr Xabcde +do_test instr-1.46 { + db eval {SELECT instr($longstr,'X');} +} {106497} +do_test instr-1.47 { + db eval {SELECT instr($longstr,'Y');} +} {0} +do_test instr-1.48 { + db eval {SELECT instr($longstr,'Xa');} +} {106497} +do_test instr-1.49 { + db eval {SELECT instr($longstr,'zXa');} +} {106496} +set longstr [string map {a ä} $longstr] +do_test instr-1.50 { + db eval {SELECT instr($longstr,'X');} +} {106497} +do_test instr-1.51 { + db eval {SELECT instr($longstr,'Y');} +} {0} +do_test instr-1.52 { + db eval {SELECT instr($longstr,'Xä');} +} {106497} +do_test instr-1.53 { + db eval {SELECT instr($longstr,'zXä');} +} {106496} +do_test instr-1.54 { + db eval {SELECT instr(x'78c3a4e282ac79','x');} +} {1} +do_test instr-1.55 { + db eval {SELECT instr(x'78c3a4e282ac79','y');} +} {4} +do_test instr-1.56 { + db eval {SELECT instr(x'78c3a4e282ac79',x'79');} +} {7} +do_test instr-1.57 { + db eval {SELECT instr('xä€y',x'79');} +} {4} + + +finish_test From e8abb4cad359b6119c9e49cf4e46a732123b232e Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 2 Nov 2012 18:24:57 +0000 Subject: [PATCH 02/10] Fix an out-of-date comment. No changes to code. FossilOrigin-Name: 10cc12b16b2f1ae4e6b3a84cef5a44564d282e9c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 7 ++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 144abcc80e..1cfc75f489 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enable\sthe\suse\sof\scoroutines\sas\san\salternative\sto\smanifesting\sviews\sused\nin\sa\sFROM\sclause. -D 2012-10-30T18:09:46.180 +C Fix\san\sout-of-date\scomment.\s\sNo\schanges\sto\scode. +D 2012-11-02T18:24:57.937 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -130,7 +130,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c 9b8d308979114991e5dc7cee958316e07186941d -F src/expr.c 152ba793a8747061c0c332857d0e4d4fd52d4397 +F src/expr.c eec289bcac90fb13ada9ef184a4d9bb84f5aa68e F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c82a04e7a92bb728f9ab972b76590403283be2af F src/func.c cbb90dc84b22eea25caf39528d342279e61b8898 @@ -1021,7 +1021,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P cbd8fddf3b4cde840279502e1e9b151bb4bd42f0 f83aa0de8470748b3cd0bff232aeea3baf8dae53 -R 4d92f802c3d1be35ade1de0afef59aa0 +P 9dca18f5fea84afbecb314ee1cdfb98430656af3 +R 3ba2075c2bb54e4c430b6beca83153a6 U drh -Z 3cf95a6ff7a3079d84c74ccc0794b887 +Z 23b76a34e07f1ecdfd7e7199b52cce1c diff --git a/manifest.uuid b/manifest.uuid index 7e30236ca5..fb84c6aab1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9dca18f5fea84afbecb314ee1cdfb98430656af3 \ No newline at end of file +10cc12b16b2f1ae4e6b3a84cef5a44564d282e9c \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 3eee3c6d69..d504be1392 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4043,9 +4043,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ } /* -** Analyze the given expression looking for aggregate functions and -** for variables that need to be added to the pParse->aAgg[] array. -** Make additional entries to the pParse->aAgg[] array as necessary. +** Analyze the pExpr expression looking for aggregate functions and +** for variables that need to be added to AggInfo object that pNC->pAggInfo +** points to. Additional entries are made on the AggInfo object as +** necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ResolveExprNames(). From 6e83a57f43624ab118976f732ede4eb46cb95372 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 2 Nov 2012 18:48:49 +0000 Subject: [PATCH 03/10] Proposed fix for ticket [bfbf38e5e9]. FossilOrigin-Name: 18ae030dad30303129186738c27cdc4ba06362b9 --- manifest | 15 +++++++++------ manifest.uuid | 2 +- src/expr.c | 4 +++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 1cfc75f489..7cf290f29e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sout-of-date\scomment.\s\sNo\schanges\sto\scode. -D 2012-11-02T18:24:57.937 +C Proposed\sfix\sfor\sticket\s[bfbf38e5e9]. +D 2012-11-02T18:48:49.928 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -130,7 +130,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c 9b8d308979114991e5dc7cee958316e07186941d -F src/expr.c eec289bcac90fb13ada9ef184a4d9bb84f5aa68e +F src/expr.c 3b25a95f3d309403940ba4a3212f197b8b6251d5 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c82a04e7a92bb728f9ab972b76590403283be2af F src/func.c cbb90dc84b22eea25caf39528d342279e61b8898 @@ -1021,7 +1021,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 9dca18f5fea84afbecb314ee1cdfb98430656af3 -R 3ba2075c2bb54e4c430b6beca83153a6 +P 10cc12b16b2f1ae4e6b3a84cef5a44564d282e9c +R 8a1bfe0b9ce6f93a26fa652a9a697188 +T *branch * ticket-bfbf38e5e9 +T *sym-ticket-bfbf38e5e9 * +T -sym-trunk * U drh -Z 23b76a34e07f1ecdfd7e7199b52cce1c +Z bedb5a372edd83ae79e50e9ef5149dad diff --git a/manifest.uuid b/manifest.uuid index fb84c6aab1..446670037e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -10cc12b16b2f1ae4e6b3a84cef5a44564d282e9c \ No newline at end of file +18ae030dad30303129186738c27cdc4ba06362b9 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index d504be1392..ae828489a6 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4030,8 +4030,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ ExprSetIrreducible(pExpr); pExpr->iAgg = (i16)i; pExpr->pAggInfo = pAggInfo; + return WRC_Prune; + }else{ + return WRC_Continue; } - return WRC_Prune; } } return WRC_Continue; From e0b2d5dabbc73a5fc25f3f314853321c5ea3d978 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 2 Nov 2012 19:08:31 +0000 Subject: [PATCH 04/10] Adding test cases for ticket [bfbf38e5e9956a] FossilOrigin-Name: 62ebfa747635a5593759ea2a28166d054c8eee8a --- manifest | 15 ++--- manifest.uuid | 2 +- test/aggnested.test | 160 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 7cf290f29e..dd1f5d296c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Proposed\sfix\sfor\sticket\s[bfbf38e5e9]. -D 2012-11-02T18:48:49.928 +C Adding\stest\scases\sfor\sticket\s[bfbf38e5e9956a] +D 2012-11-02T19:08:31.592 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b F src/where.c 6a753aa008de6494e64dd265a27afbb0ad80ccf5 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 -F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00 +F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 52fc8dee494092031a556911d404ca30a749a30b F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748 @@ -1021,10 +1021,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 10cc12b16b2f1ae4e6b3a84cef5a44564d282e9c -R 8a1bfe0b9ce6f93a26fa652a9a697188 -T *branch * ticket-bfbf38e5e9 -T *sym-ticket-bfbf38e5e9 * -T -sym-trunk * +P 18ae030dad30303129186738c27cdc4ba06362b9 +R 0bddd84c58415ef799271c8a76e36e44 U drh -Z bedb5a372edd83ae79e50e9ef5149dad +Z d5af1bf3eac39af6d9724e55a6d42186 diff --git a/manifest.uuid b/manifest.uuid index 446670037e..38c8e220ab 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -18ae030dad30303129186738c27cdc4ba06362b9 \ No newline at end of file +62ebfa747635a5593759ea2a28166d054c8eee8a \ No newline at end of file diff --git a/test/aggnested.test b/test/aggnested.test index 22f0fb6b9a..6e2fd6554b 100644 --- a/test/aggnested.test +++ b/test/aggnested.test @@ -68,4 +68,164 @@ do_test aggnested-2.0 { } {A,B,B 3 33 333 3333} db2 close +##################### Test cases for ticket [bfbf38e5e9956ac69f] ############ +# +# This first test case is the original problem report: +do_test aggnested-3.0 { + db eval { + CREATE TABLE AAA ( + aaa_id INTEGER PRIMARY KEY AUTOINCREMENT + ); + CREATE TABLE RRR ( + rrr_id INTEGER PRIMARY KEY AUTOINCREMENT, + rrr_date INTEGER NOT NULL, + rrr_aaa INTEGER + ); + CREATE TABLE TTT ( + ttt_id INTEGER PRIMARY KEY AUTOINCREMENT, + target_aaa INTEGER NOT NULL, + source_aaa INTEGER NOT NULL + ); + insert into AAA (aaa_id) values (2); + insert into TTT (ttt_id, target_aaa, source_aaa) + values (4469, 2, 2); + insert into TTT (ttt_id, target_aaa, source_aaa) + values (4476, 2, 1); + insert into RRR (rrr_id, rrr_date, rrr_aaa) + values (0, 0, NULL); + insert into RRR (rrr_id, rrr_date, rrr_aaa) + values (2, 4312, 2); + SELECT i.aaa_id, + (SELECT sum(CASE WHEN (t.source_aaa == i.aaa_id) THEN 1 ELSE 0 END) + FROM TTT t + ) AS segfault + FROM + (SELECT curr.rrr_aaa as aaa_id + FROM RRR curr + -- you also can comment out the next line + -- it causes segfault to happen after one row is outputted + INNER JOIN AAA a ON (curr.rrr_aaa = aaa_id) + LEFT JOIN RRR r ON (r.rrr_id <> 0 AND r.rrr_date < curr.rrr_date) + GROUP BY curr.rrr_id + HAVING r.rrr_date IS NULL + ) i; + } +} {2 1} + +# Further variants of the test case, as found in the ticket +# +do_test aggnested-3.1 { + db eval { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1 ( + id1 INTEGER PRIMARY KEY AUTOINCREMENT, + value1 INTEGER + ); + INSERT INTO t1 VALUES(4469,2),(4476,1); + CREATE TABLE t2 ( + id2 INTEGER PRIMARY KEY AUTOINCREMENT, + value2 INTEGER + ); + INSERT INTO t2 VALUES(0,1),(2,2); + SELECT + (SELECT sum(value2==xyz) FROM t2) + FROM + (SELECT curr.value1 as xyz + FROM t1 AS curr LEFT JOIN t1 AS other + GROUP BY curr.id1); + } +} {1 1} +do_test aggnested-3.2 { + db eval { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1 ( + id1 INTEGER, + value1 INTEGER, + x1 INTEGER + ); + INSERT INTO t1 VALUES(4469,2,98),(4469,1,99),(4469,3,97); + CREATE TABLE t2 ( + value2 INTEGER + ); + INSERT INTO t2 VALUES(1); + SELECT + (SELECT sum(value2==xyz) FROM t2) + FROM + (SELECT value1 as xyz, max(x1) AS pqr + FROM t1 + GROUP BY id1); + } +} {0} +do_test aggnested-3.3 { + db eval { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(id1, value1); + INSERT INTO t1 VALUES(4469,2),(4469,1); + CREATE TABLE t2 (value2); + INSERT INTO t2 VALUES(1); + SELECT (SELECT sum(value2=value1) FROM t2), max(value1) + FROM t1 + GROUP BY id1; + } +} {0 2} + +# A batch of queries all doing approximately the same operation involving +# two nested aggregate queries. +# +do_test aggnested-3.11 { + db eval { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(id1, value1); + INSERT INTO t1 VALUES(4469,12),(4469,11),(4470,34); + CREATE INDEX t1id1 ON t1(id1); + CREATE TABLE t2 (value2); + INSERT INTO t2 VALUES(12),(34),(34); + INSERT INTO t2 SELECT value2 FROM t2; + + SELECT max(value1), (SELECT count(*) FROM t2 WHERE value2=max(value1)) + FROM t1 + GROUP BY id1; + } +} {12 2 34 4} +do_test aggnested-3.12 { + db eval { + SELECT max(value1), (SELECT count(*) FROM t2 WHERE value2=value1) + FROM t1 + GROUP BY id1; + } +} {12 2 34 4} +do_test aggnested-3.13 { + db eval { + SELECT value1, (SELECT sum(value2=value1) FROM t2) + FROM t1; + } +} {12 2 11 0 34 4} +do_test aggnested-3.14 { + db eval { + SELECT value1, (SELECT sum(value2=value1) FROM t2) + FROM t1 + WHERE value1 IN (SELECT max(value1) FROM t1 GROUP BY id1); + } +} {12 2 34 4} +do_test aggnested-3.15 { + # FIXME: If case 3.16 works, then this case really ought to work too... + catchsql { + SELECT max(value1), (SELECT sum(value2=max(value1)) FROM t2) + FROM t1 + GROUP BY id1; + } +} {1 {misuse of aggregate function max()}} +do_test aggnested-3.16 { + db eval { + SELECT max(value1), (SELECT sum(value2=value1) FROM t2) + FROM t1 + GROUP BY id1; + } +} {12 2 34 4} + + finish_test From 46f7d98c0cdf907804c7904414f5097f914a1f27 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 6 Nov 2012 18:41:41 +0000 Subject: [PATCH 05/10] In test_quota.c, provide a work-around for the missing _chsize_s() function in mingw. FossilOrigin-Name: 6b4979e86c05f2da2c5fff67ea7feec5fa56756a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/test_quota.c | 8 +++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 6f81a34154..f2e01a9377 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sINSTR()\sSQL\sfunction. -D 2012-11-05T13:51:58.781 +C In\stest_quota.c,\sprovide\sa\swork-around\sfor\sthe\smissing\s_chsize_s()\sfunction\nin\smingw. +D 2012-11-06T18:41:41.558 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -215,7 +215,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25 F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c e5fdb7d28e5afae1b619922804e544db0041ec81 +F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5 F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 @@ -1022,7 +1022,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 4f7dfc32aad1c552d09dc8fefb40cc3656d74883 49ccae964f3a8ae5aab87f56503121e09424545f -R 9c69fd93cfd942af384711e31b335f2e +P a4c181cbcf9b8baa6e07501a93ef81603d91ba7d +R ffefeab3454a555d2c573fd19c705ae8 U drh -Z 948b87ce69fca256505028584053ea0a +Z 21f5933910ea4269dcf611e571177ae9 diff --git a/manifest.uuid b/manifest.uuid index 0fa53a0836..371ba5e69b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a4c181cbcf9b8baa6e07501a93ef81603d91ba7d \ No newline at end of file +6b4979e86c05f2da2c5fff67ea7feec5fa56756a \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index e1ec12d371..166a512f18 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -1179,7 +1179,13 @@ int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){ rc = ftruncate(fileno(p->f), szNew); #endif #if SQLITE_OS_WIN - rc = _chsize_s(_fileno(p->f), szNew); +# if defined(__MINGW32__) && defined(SQLITE_TEST) + /* _chsize_s() is missing from MingW (as of 2012-11-06). Use + ** _chsize() as a work-around for testing purposes. */ + rc = _chsize(_fileno(p->f), (long)szNew); +# else + rc = _chsize_s(_fileno(p->f), szNew); +# endif #endif if( pFile && rc==0 ){ quotaGroup *pGroup = pFile->pGroup; From 70cb28fc0e6cc21c4ee87e374354f0b271d925fe Mon Sep 17 00:00:00 2001 From: mistachkin Date: Tue, 6 Nov 2012 20:39:11 +0000 Subject: [PATCH 06/10] Adjust the SQLITE_DBSTATUS_STMT_USED calculation to take the modified usage of sqlite3VdbeClearObject() into account. FossilOrigin-Name: 82eb7eadb8c76b3af8c811d791f87a634c35935f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/status.c | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index f2e01a9377..46d197a9d4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\stest_quota.c,\sprovide\sa\swork-around\sfor\sthe\smissing\s_chsize_s()\sfunction\nin\smingw. -D 2012-11-06T18:41:41.558 +C Adjust\sthe\sSQLITE_DBSTATUS_STMT_USED\scalculation\sto\stake\sthe\smodified\susage\sof\ssqlite3VdbeClearObject()\sinto\saccount. +D 2012-11-06T20:39:11.759 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -181,7 +181,7 @@ F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h f29ed6fbbf80a6d9ac8aae9998ecae2b8d72e0ae F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d -F src/status.c 53463144deb5dfac0a66b3be4dd7844b8f8a4c98 +F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 515abd8e33e82aa330eeb54675185a7e1e5b6778 F src/test1.c 936afc02766403e5debca49a1817a780e116df7e @@ -1022,7 +1022,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P a4c181cbcf9b8baa6e07501a93ef81603d91ba7d -R ffefeab3454a555d2c573fd19c705ae8 -U drh -Z 21f5933910ea4269dcf611e571177ae9 +P 6b4979e86c05f2da2c5fff67ea7feec5fa56756a +R 275b30fd4dabbb76a3c510773e928640 +U mistachkin +Z 07851b8d86e7907c3dc0dd17f564d79e diff --git a/manifest.uuid b/manifest.uuid index 371ba5e69b..8c413f9a8d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b4979e86c05f2da2c5fff67ea7feec5fa56756a \ No newline at end of file +82eb7eadb8c76b3af8c811d791f87a634c35935f \ No newline at end of file diff --git a/src/status.c b/src/status.c index 9b0df8001c..28349e6d3d 100644 --- a/src/status.c +++ b/src/status.c @@ -209,6 +209,7 @@ int sqlite3_db_status( db->pnBytesFreed = &nByte; for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ sqlite3VdbeClearObject(db, pVdbe); + sqlite3DbFree(db, pVdbe); } db->pnBytesFreed = 0; From 782d68a4cdc0e089899855e228e3dd78a02724e3 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 9 Nov 2012 17:59:26 +0000 Subject: [PATCH 07/10] Try to take into account the cost of inner loops when selecting which table of a join to use for the outer loop. FossilOrigin-Name: 942556342a332b04a11169bb04f387d741ef9488 --- manifest | 23 +++++---- manifest.uuid | 2 +- src/sqliteInt.h | 1 + src/where.c | 27 ++++++++++- test/orderby1.test | 94 ++++++++++++++++++------------------ test/whereE.test | 62 ++++++++++++++++++++++++ test/whereF.test | 115 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 265 insertions(+), 59 deletions(-) create mode 100644 test/whereE.test create mode 100644 test/whereF.test diff --git a/manifest b/manifest index 46d197a9d4..65706de517 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjust\sthe\sSQLITE_DBSTATUS_STMT_USED\scalculation\sto\stake\sthe\smodified\susage\sof\ssqlite3VdbeClearObject()\sinto\saccount. -D 2012-11-06T20:39:11.759 +C Try\sto\stake\sinto\saccount\sthe\scost\sof\sinner\sloops\swhen\sselecting\swhich\stable\nof\sa\sjoin\sto\suse\sfor\sthe\souter\sloop. +D 2012-11-09T17:59:26.161 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -179,7 +179,7 @@ F src/shell.c 24cd0aa74aff73ea08594629faead564c4c2a286 F src/sqlite.h.in c7be05ad191d2634292fcc77bdb2bcfa4526eb98 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 -F src/sqliteInt.h f29ed6fbbf80a6d9ac8aae9998ecae2b8d72e0ae +F src/sqliteInt.h 79c00e24d84541c3117ef34ce09c5749dcdcba25 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -249,7 +249,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 6a753aa008de6494e64dd265a27afbb0ad80ccf5 +F src/where.c b97f14d4ce618ceb18138238b1bd028cf02014b4 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -636,7 +636,7 @@ F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test ef4f7c40df81b9a4303a718433d34052f07db47d +F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 F test/pager1.test 07116f72a61960b882952e7472cc2846d161d6e2 @@ -974,6 +974,8 @@ F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5 F test/whereD.test 3f3ee93825c94804f1fc91eef2de0d365981759a +F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d +F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 @@ -1022,7 +1024,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 6b4979e86c05f2da2c5fff67ea7feec5fa56756a -R 275b30fd4dabbb76a3c510773e928640 -U mistachkin -Z 07851b8d86e7907c3dc0dd17f564d79e +P 82eb7eadb8c76b3af8c811d791f87a634c35935f +R 6e69028f10fbf48578845dd76c89b910 +T *branch * inner-loop-cost +T *sym-inner-loop-cost * +T -sym-trunk * +U drh +Z 386f6fc4840a28b57311013bb9458533 diff --git a/manifest.uuid b/manifest.uuid index 8c413f9a8d..85eae6eacd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -82eb7eadb8c76b3af8c811d791f87a634c35935f \ No newline at end of file +942556342a332b04a11169bb04f387d741ef9488 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e44ce7b7e8..eb779253c9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1967,6 +1967,7 @@ struct WhereLevel { } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; + double rOptCost; /* "Optimal" cost for this level */ /* The following field is really not part of the current level. But ** we need a place to cache virtual table index information for each diff --git a/src/where.c b/src/where.c index 38f6f1436f..5fa40994fe 100644 --- a/src/where.c +++ b/src/where.c @@ -4744,6 +4744,16 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } } +/* +** Return TRUE if the wsFlags indicate that a full table scan (or a +** full scan of a covering index) is indicated. +*/ +static int isFullscan(unsigned wsFlags){ + if( wsFlags & WHERE_COVER_SCAN ) return 1; + if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ) return 1; + return 0; +} + /* ** Generate the beginning of the loop used for WHERE clause processing. @@ -5102,6 +5112,19 @@ WhereInfo *sqlite3WhereBegin( if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ notIndexed |= m; } + if( isOptimal ){ + pWInfo->a[j].rOptCost = sWBI.cost.rCost; + }else if( iFroma[j].rOptCost)); + sWBI.cost.rCost /= pWInfo->a[j].rOptCost; + } /* Conditions under which this table becomes the best so far: ** @@ -5126,8 +5149,8 @@ WhereInfo *sqlite3WhereBegin( */ if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ - || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 - || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) + || isFullscan(bestPlan.plan.wsFlags) + || !isFullscan(sWBI.cost.plan.wsFlags)) && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */ || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */ diff --git a/test/orderby1.test b/test/orderby1.test index 2001e34009..f459fc8195 100644 --- a/test/orderby1.test +++ b/test/orderby1.test @@ -48,7 +48,7 @@ do_test 1.0 { } {} do_test 1.1a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -57,7 +57,7 @@ do_test 1.1a { do_test 1.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -66,7 +66,7 @@ do_test 1.1b { # do_test 1.2a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -75,7 +75,7 @@ do_test 1.2a { do_test 1.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -85,13 +85,13 @@ do_test 1.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 1.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -101,53 +101,53 @@ db cache flush # do_test 1.4a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 1.4b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 1.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {~/ORDER BY/} ;# optimized out do_test 1.5a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 1.5b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 1.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {~/ORDER BY/} ;# optimized out do_test 1.6a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 1.6b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 1.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {~/ORDER BY/} ;# ORDER BY optimized-out @@ -183,7 +183,7 @@ do_test 2.0 { } {} do_test 2.1a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -192,19 +192,19 @@ do_test 2.1a { do_test 2.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {~/ORDER BY/} ;# ORDER BY optimized out do_test 2.1c { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.1d { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -213,7 +213,7 @@ do_test 2.1d { # do_test 2.2a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -222,7 +222,7 @@ do_test 2.2a { do_test 2.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -232,13 +232,13 @@ do_test 2.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -248,53 +248,53 @@ db cache flush # do_test 2.4a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 2.4b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 2.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {~/ORDER BY/} ;# optimized out do_test 2.5a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 2.5b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 2.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {~/ORDER BY/} ;# optimized out do_test 2.6a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 2.6b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 2.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -330,7 +330,7 @@ do_test 3.0 { } {} do_test 3.1a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} @@ -339,7 +339,7 @@ do_test 3.1a { do_test 3.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -348,7 +348,7 @@ do_test 3.1b { # do_test 3.2a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} @@ -357,7 +357,7 @@ do_test 3.2a { do_test 3.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -367,13 +367,13 @@ do_test 3.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 3.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -383,54 +383,54 @@ db cache flush # do_test 3.4a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 3.4b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} ;# verify same order after sorting do_test 3.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {~/ORDER BY/} ;# optimized out do_test 3.5a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 3.5b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 3.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {~/ORDER BY/} ;# optimzed out do_test 3.6a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 3.6b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 3.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {~/ORDER BY/} ;# inverted ASC/DESC is optimized out diff --git a/test/whereE.test b/test/whereE.test new file mode 100644 index 0000000000..e686a4628e --- /dev/null +++ b/test/whereE.test @@ -0,0 +1,62 @@ +# 2012 November 9 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the query planner to make sure it +# is making good planning decisions. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereE + +do_execsql_test 1.1 { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33); + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + ALTER TABLE t1 ADD COLUMN c; + UPDATE t1 SET c=a*rowid+10000; + CREATE INDEX t1ab ON t1(a,b); + + CREATE TABLE t2(x,y); + INSERT INTO t2 VALUES(4,44),(5,55),(6,66),(7,77); + INSERT INTO t2 SELECT x+4, (x+4)*11 FROM t2; + INSERT INTO t2 SELECT x+8, (x+8)*11 FROM t2; + INSERT INTO t2 SELECT x+16, (x+16)*11 FROM t2; + INSERT INTO t2 SELECT x+32, (x+32)*11 FROM t2; + INSERT INTO t2 SELECT x+64, (x+32)*11 FROM t2; + ALTER TABLE t2 ADD COLUMN z; + UPDATE t2 SET z=2; + CREATE UNIQUE INDEX t2zx ON t2(z,x); + + EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +do_execsql_test 1.2 { + EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +do_execsql_test 1.3 { + ANALYZE; + EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +do_execsql_test 1.4 { + EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} + +finish_test diff --git a/test/whereF.test b/test/whereF.test new file mode 100644 index 0000000000..57bdbee058 --- /dev/null +++ b/test/whereF.test @@ -0,0 +1,115 @@ +# 2012 November 9 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# Test cases for query planning decisions. + + +# +# The tests in this file demonstrate the behaviour of the query planner +# in determining the order in which joined tables are scanned. +# +# Assume there are two tables being joined - t1 and t2. Each has a cost +# if it is the outer loop, and a cost if it is the inner loop. As follows: +# +# t1(outer) - cost of scanning t1 as the outer loop. +# t1(inner) - cost of scanning t1 as the inner loop. +# t2(outer) - cost of scanning t2 as the outer loop. +# t2(inner) - cost of scanning t2 as the inner loop. +# +# Depending on the order in which the planner nests the scans, the total +# cost of the join query is one of: +# +# t1(outer) * t2(inner) +# t2(outer) * t1(inner) +# +# The tests in this file attempt to verify that the planner nests joins in +# the correct order when the following are true: +# +# + (t1(outer) * t2(inner)) > (t1(inner) * t2(outer) +# + t1(outer) < t2(outer) +# +# In other words, when the best overall query plan has t2 as the outer loop, +# but when the outer loop is considered independent of the inner, t1 is the +# most efficient choice. +# +# In order to make them more predictable, automatic indexes are turned off for +# the tests in this file. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix x + +do_execsql_test 1.0 { + PRAGMA automatic_index = 0; + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(d, e, f); + CREATE UNIQUE INDEX i1 ON t1(a); + CREATE UNIQUE INDEX i2 ON t2(d); +} {} + +foreach {tn sql} { + 1 "SELECT * FROM t1, t2 WHERE t1.a=t2.e AND t2.d? AND t2.d>t1.c AND t1.b=t2.e" + 2 "SELECT * FROM t2, t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" + 3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" +} { + do_test 2.$tn { + db eval "EXPLAIN QUERY PLAN $sql" + } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} +} + +do_execsql_test 3.0 { + DROP TABLE t1; + DROP TABLE t2; + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(d, e, f); + + CREATE UNIQUE INDEX i1 ON t1(a, b); + CREATE INDEX i2 ON t2(d); +} {} + +foreach {tn sql} { + 1 {SELECT t1.a, t1.b, t2.d, t2.e FROM t1, t2 + WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} + + 2 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2, t1 + WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} + + 3 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2 CROSS JOIN t1 + WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} +} { + do_test 3.$tn { + db eval "EXPLAIN QUERY PLAN $sql" + } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} +} + +finish_test From ada796bbaa9ffb52ef68e177d03aa2bd6d639097 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 9 Nov 2012 18:22:26 +0000 Subject: [PATCH 08/10] Disable the table selection rule that tried to prevent full table scans from migrating to the outer loop unless they were optimal. The new scaling of outer-loop costs by cost of inner loops obviates the need for that step. And, in fact, that step causes problems with the new inner-loop cost accounting. FossilOrigin-Name: 51bfd63b7f9fe53831570ad124c932cb3582b104 --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/where.c | 17 ++--------------- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 65706de517..66c67bce3f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Try\sto\stake\sinto\saccount\sthe\scost\sof\sinner\sloops\swhen\sselecting\swhich\stable\nof\sa\sjoin\sto\suse\sfor\sthe\souter\sloop. -D 2012-11-09T17:59:26.161 +C Disable\sthe\stable\sselection\srule\sthat\stried\sto\sprevent\sfull\stable\sscans\sfrom\nmigrating\sto\sthe\souter\sloop\sunless\sthey\swere\soptimal.\s\sThe\snew\sscaling\sof\s\nouter-loop\scosts\sby\scost\sof\sinner\sloops\sobviates\sthe\sneed\sfor\sthat\sstep.\s\sAnd,\nin\sfact,\sthat\sstep\scauses\sproblems\swith\sthe\snew\sinner-loop\scost\saccounting. +D 2012-11-09T18:22:26.026 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -249,7 +249,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c b97f14d4ce618ceb18138238b1bd028cf02014b4 +F src/where.c 832e33fefbe5ba751c1f5a06e63de98be95e56f2 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1024,10 +1024,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 82eb7eadb8c76b3af8c811d791f87a634c35935f -R 6e69028f10fbf48578845dd76c89b910 -T *branch * inner-loop-cost -T *sym-inner-loop-cost * -T -sym-trunk * +P 942556342a332b04a11169bb04f387d741ef9488 +R 283b8e4433f3480f37a4748d3a98dd6b U drh -Z 386f6fc4840a28b57311013bb9458533 +Z d761059332f6b35837425e120092c25f diff --git a/manifest.uuid b/manifest.uuid index 85eae6eacd..6f8dcc7f72 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -942556342a332b04a11169bb04f387d741ef9488 \ No newline at end of file +51bfd63b7f9fe53831570ad124c932cb3582b104 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 5fa40994fe..20bd90979e 100644 --- a/src/where.c +++ b/src/where.c @@ -4744,16 +4744,6 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } } -/* -** Return TRUE if the wsFlags indicate that a full table scan (or a -** full scan of a covering index) is indicated. -*/ -static int isFullscan(unsigned wsFlags){ - if( wsFlags & WHERE_COVER_SCAN ) return 1; - if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ) return 1; - return 0; -} - /* ** Generate the beginning of the loop used for WHERE clause processing. @@ -5132,8 +5122,8 @@ WhereInfo *sqlite3WhereBegin( ** yet run. (In other words, it must not depend on tables ** in inner loops.) ** - ** (2) A full-table-scan plan cannot supercede indexed plan unless - ** the full-table-scan is an "optimal" plan as defined above. + ** (2) (This rule was removed on 2012-11-09. The scaling of the + ** cost using the optimal scan cost made this rule obsolete.) ** ** (3) All tables have an INDEXED BY clause or this table lacks an ** INDEXED BY clause or this table uses the specific @@ -5148,9 +5138,6 @@ WhereInfo *sqlite3WhereBegin( ** is defined by the compareCost() function above. */ if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ - && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ - || isFullscan(bestPlan.plan.wsFlags) - || !isFullscan(sWBI.cost.plan.wsFlags)) && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */ || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */ From 9fc5b4a5399144db31b1bf88632ea615dcd5fb2f Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 9 Nov 2012 20:17:26 +0000 Subject: [PATCH 09/10] Change os_unix.c to propagate ENOENT errors back to sqlite as SQLITE_IOERR_DELETE_NOENT. Have SQLite ignore these where they are benign and propagate them back to the caller where they may indicate a file-system malfunction of some description. FossilOrigin-Name: bed9c172ce624ab7b5b9de9ad42444891717ad9a --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/os_unix.c | 9 +++++++-- src/pager.c | 1 + src/sqlite.h.in | 1 + test/pager1.test | 28 ++++++++++++++++++++++++++++ 6 files changed, 48 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index be8991af1e..8a494b2e26 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Take\sinto\saccount\sthe\scost\sof\sinner\sloops\swhen\sselecting\swhich\stable\sof\sa\sjoin\nto\suse\sfor\sthe\snext\souter\sloop. -D 2012-11-09T18:32:05.073 +C Change\sos_unix.c\sto\spropagate\sENOENT\serrors\sback\sto\ssqlite\sas\sSQLITE_IOERR_DELETE_NOENT.\sHave\sSQLite\signore\sthese\swhere\sthey\sare\sbenign\sand\spropagate\sthem\sback\sto\sthe\scaller\swhere\sthey\smay\sindicate\sa\sfile-system\smalfunction\sof\ssome\sdescription. +D 2012-11-09T20:17:26.376 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -160,9 +160,9 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c 603d020fe6c58047794cc72c05c7c8f4a82a0579 +F src/os_unix.c 1f7c7f2a3b2c66590c7bab75e4b4d28003b316a9 F src/os_win.c 43ec1285357e5d5d919cb0492eac775c58ad7d12 -F src/pager.c ee59fef31673d5124413c5a801cfd9ef3e6766d3 +F src/pager.c ed53fe75a269c1d67645fe079ea0f3f0ce6492d5 F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0 F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 @@ -176,7 +176,7 @@ F src/resolve.c 7b986a715ac281643309c29257bb58cfae7aa810 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 3a8baf4719f9723b4e0b43f2baa60692d0d921f8 F src/shell.c 24cd0aa74aff73ea08594629faead564c4c2a286 -F src/sqlite.h.in c7be05ad191d2634292fcc77bdb2bcfa4526eb98 +F src/sqlite.h.in 2a0d1234242d75e19e297db99f0925fc9f021e85 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h 79c00e24d84541c3117ef34ce09c5749dcdcba25 @@ -639,7 +639,7 @@ F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 -F test/pager1.test 07116f72a61960b882952e7472cc2846d161d6e2 +F test/pager1.test f4c57e14583da2183fe31555c67fb32feda96092 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442 @@ -1024,7 +1024,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 82eb7eadb8c76b3af8c811d791f87a634c35935f 51bfd63b7f9fe53831570ad124c932cb3582b104 -R 283b8e4433f3480f37a4748d3a98dd6b -U drh -Z fb5e55182e15313d5ce5bacd4603beff +P 3f87f4593b631819609248c8f1370c1e19465eb0 +R 2f3e513245018c14d7af93e651fbc22c +U dan +Z 1e3c59db135f9831a4bbf3c3ac743265 diff --git a/manifest.uuid b/manifest.uuid index 0844db388b..734ccb5346 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3f87f4593b631819609248c8f1370c1e19465eb0 \ No newline at end of file +bed9c172ce624ab7b5b9de9ad42444891717ad9a \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 9b6c9401a1..1de88f942e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5374,8 +5374,13 @@ static int unixDelete( int rc = SQLITE_OK; UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); - if( osUnlink(zPath)==(-1) && errno!=ENOENT ){ - return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); + if( osUnlink(zPath)==(-1) ){ + if( errno==ENOENT ){ + rc = SQLITE_IOERR_DELETE_NOENT; + }else{ + rc = SQLITE_IOERR_DELETE; + } + return unixLogError(rc, "unlink", zPath); } #ifndef SQLITE_DISABLE_DIRSYNC if( (dirSync & 1)!=0 ){ diff --git a/src/pager.c b/src/pager.c index a96dc45b82..7c039e7a76 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3159,6 +3159,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){ if( rc ) return rc; if( nPage==0 ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); + if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK; isWal = 0; }else{ rc = sqlite3OsAccess( diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 0d619e96c0..520cccd042 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -469,6 +469,7 @@ int sqlite3_exec( #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) +#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) diff --git a/test/pager1.test b/test/pager1.test index fac434037e..6849e55bbd 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -2487,4 +2487,32 @@ do_test pager1-32.1 { # Cleanup 20MB file left by the previous test. forcedelete test.db +#------------------------------------------------------------------------- +# Test that if a transaction is committed in journal_mode=DELETE mode, +# and the call to unlink() returns an ENOENT error, the COMMIT does not +# succeed. +# +if {$::tcl_platform(platform)=="unix"} { + do_test pager1-33.1 { + sqlite3 db test.db + execsql { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('two'); + BEGIN; + INSERT INTO t1 VALUES('three'); + INSERT INTO t1 VALUES('four'); + } + forcedelete bak-journal + file rename test.db-journal bak-journal + + catchsql COMMIT + } {1 {disk I/O error}} + + do_test pager1-33.2 { + file rename bak-journal test.db-journal + execsql { SELECT * FROM t1 } + } {one two} +} + finish_test From b43081675d225ef7c5dfbab3adfbeb6c9b509ed2 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 9 Nov 2012 21:40:02 +0000 Subject: [PATCH 10/10] Only log unlink() errors if the error is something other than SQLITE_IOERR_DELETE_NOENT. The error is still reported up the stack, it is simply not added to the sqlite3_log(). FossilOrigin-Name: 5a3b07f0f5dfae7eea870303f52f37d6a17f1da2 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_unix.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 8a494b2e26..028b6852d1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sos_unix.c\sto\spropagate\sENOENT\serrors\sback\sto\ssqlite\sas\sSQLITE_IOERR_DELETE_NOENT.\sHave\sSQLite\signore\sthese\swhere\sthey\sare\sbenign\sand\spropagate\sthem\sback\sto\sthe\scaller\swhere\sthey\smay\sindicate\sa\sfile-system\smalfunction\sof\ssome\sdescription. -D 2012-11-09T20:17:26.376 +C Only\slog\sunlink()\serrors\sif\sthe\serror\sis\ssomething\sother\sthan\nSQLITE_IOERR_DELETE_NOENT.\s\sThe\serror\sis\sstill\sreported\sup\sthe\sstack,\sit\nis\ssimply\snot\sadded\sto\sthe\ssqlite3_log(). +D 2012-11-09T21:40:02.069 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -160,7 +160,7 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 -F src/os_unix.c 1f7c7f2a3b2c66590c7bab75e4b4d28003b316a9 +F src/os_unix.c f0753566e1125d8b2eef6dd080b48ed91a83d424 F src/os_win.c 43ec1285357e5d5d919cb0492eac775c58ad7d12 F src/pager.c ed53fe75a269c1d67645fe079ea0f3f0ce6492d5 F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0 @@ -1024,7 +1024,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 3f87f4593b631819609248c8f1370c1e19465eb0 -R 2f3e513245018c14d7af93e651fbc22c -U dan -Z 1e3c59db135f9831a4bbf3c3ac743265 +P bed9c172ce624ab7b5b9de9ad42444891717ad9a +R 6c7c8f8d3a3d00e4614865ddb6f518c4 +U drh +Z 81d94dfa08446549954e693bf8235ef9 diff --git a/manifest.uuid b/manifest.uuid index 734ccb5346..eae5c05106 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bed9c172ce624ab7b5b9de9ad42444891717ad9a \ No newline at end of file +5a3b07f0f5dfae7eea870303f52f37d6a17f1da2 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 1de88f942e..ca62139430 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5378,9 +5378,9 @@ static int unixDelete( if( errno==ENOENT ){ rc = SQLITE_IOERR_DELETE_NOENT; }else{ - rc = SQLITE_IOERR_DELETE; + rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); } - return unixLogError(rc, "unlink", zPath); + return rc; } #ifndef SQLITE_DISABLE_DIRSYNC if( (dirSync & 1)!=0 ){