From d591a5b93d4f84c3e0a3080109936be22292607f Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 26 Apr 2024 12:01:17 +0000 Subject: [PATCH 1/8] Add test demonstrating the problem at [forum:/forumpost/c243b8f856|forum post c243b8f856]. No fix yet. FossilOrigin-Name: 1685495c0a00238c9c92cce01af8108204a2fad22433ed3e7bba3c9da9ee0766 --- manifest | 16 +++-- manifest.uuid | 2 +- test/bestindexC.test | 137 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 test/bestindexC.test diff --git a/manifest b/manifest index 0c6764a1bf..5aaf6f32cc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvement\sto\sthe\sway\sthat\saffinity\sis\sdetermined\sfor\scolumns\sof\sa\ncompound\ssubquery.\s\sThe\saffinity\sis\sthe\saffinity\sof\sthe\sleft-most\narm\sof\sthe\scompound\ssubquery\sthat\shas\san\saffinity\sother\sthan\sNONE,\sadjusted\nto\saccommodate\sthe\sdata\stypes\scoming\sout\sof\sthe\sother\sarms. -D 2024-04-25T23:26:11.710 +C Add\stest\sdemonstrating\sthe\sproblem\sat\s[forum:/forumpost/c243b8f856|forum\spost\sc243b8f856].\sNo\sfix\syet. +D 2024-04-26T12:01:17.532 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -936,6 +936,7 @@ F test/bestindex8.test 333ad8c6a554b885a49b68c019166eda92b05f493a92b36b0acdf7f76 F test/bestindex9.test 1a4b93db117fd8abe74ae9be982f86aa72f01e60cd4ac541e6ede39673a451a0 F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572eef44c7f F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce +F test/bestindexC.test cddef2bfebfce49f27d93de6db070e158842e9414ade05e2ddd9f869691bf698 F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc @@ -2185,8 +2186,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d99a01a0f6e1f70f70c9a0625aeaa8a8015eba352bcfb3978eafca6df10ba5a8 bbdf22e3d989f42b963f1f2f219dfeac11db786f17ac27097ab72f72e7638a2a -R 654e0ae3f3741f82dda9d50fba2bb5a6 -U drh -Z cd9aa5444a2a196c931f4e6dcda6cddb +P e6df846f36209bac3e420dd80ce2bbbd87ab7a20b8063fce05f78a3c7ab6027e +R 86e9e2a691d55b415e3c7d753f120811 +T *branch * vtab-limit-fix +T *sym-vtab-limit-fix * +T -sym-trunk * +U dan +Z 98d2dacd3c5e1da28914a036142cb128 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d5803c8f68..80649ce5f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e6df846f36209bac3e420dd80ce2bbbd87ab7a20b8063fce05f78a3c7ab6027e \ No newline at end of file +1685495c0a00238c9c92cce01af8108204a2fad22433ed3e7bba3c9da9ee0766 \ No newline at end of file diff --git a/test/bestindexC.test b/test/bestindexC.test new file mode 100644 index 0000000000..91b8f027eb --- /dev/null +++ b/test/bestindexC.test @@ -0,0 +1,137 @@ +# 2023-10-26 +# +# 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. +# +#*********************************************************************** +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix bestindexB + +ifcapable !vtab { + finish_test + return +} + +register_tcl_module db + +proc vtab_command {lVal method args} { + switch -- $method { + xConnect { + return "CREATE TABLE t1(a)" + } + + xBestIndex { + set hdl [lindex $args 0] + set clist [$hdl constraints] + set orderby [$hdl orderby] + + set idxstr [list] + set res [list] + + set idx 0 + foreach c $clist { + array set a $c + if {$a(usable)==0} continue + if {$a(op)=="limit"} { + lappend idxstr limit + lappend res omit $idx + } + if {$a(op)=="offset"} { + lappend idxstr offset + lappend res omit $idx + } + incr idx + } + + return "cost 1000000 rows 1000000 idxnum 0 idxstr {$idxstr} $res" + } + + xFilter { + set idxstr [lindex $args 1] + set LIMIT "" + foreach a $idxstr b [lindex $args 2] { + append LIMIT " $a $b" + } + + set idx 1 + foreach v $lVal { + lappend lRow "($idx, '$v')" + incr idx + } + + return [list sql " + SELECT * FROM ( VALUES [join $lRow ,]) $LIMIT + "] + } + } + + return {} +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE x1 USING tcl(vtab_command "a b c d e f"); + CREATE VIRTUAL TABLE x2 USING tcl(vtab_command "A B C D E F a b"); +} {} + +do_execsql_test 1.1 { + CREATE TEMP TABLE t_unionall AS + SELECT * FROM x1 UNION ALL SELECT * FROM x2; + + CREATE TEMP TABLE t_intersect AS + SELECT * FROM x1 INTERSECT SELECT * FROM x2; + + CREATE TEMP TABLE t_union AS + SELECT * FROM x1 UNION SELECT * FROM x2; + + CREATE TEMP TABLE t_except AS + SELECT * FROM x1 EXCEPT SELECT * FROM x2; +} + +foreach {tn limit} { + 1 "LIMIT 8" + 2 "LIMIT 4" + 3 "LIMIT 4 OFFSET 2" + 4 "LIMIT 8 OFFSET 4" +} { + + foreach {op tbl} { + "UNION ALL" t_unionall + "UNION" t_union + "INTERSECT" t_intersect + "EXCEPT" t_except + } { + + set expect [execsql "SELECT * FROM $tbl $limit"] + do_execsql_test 1.2.$tbl.$tn "SELECT * FROM ( + SELECT * FROM x1 $op SELECT * FROM x2 + ) $limit" $expect + + } + +} + +#------------------------------------------------------------------------- +reset_db +register_tcl_module db + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE x1 USING tcl(vtab_command "a b c d e f"); + CREATE VIRTUAL TABLE x2 USING tcl(vtab_command "a b e f"); +} {} + +do_execsql_test 2.1 { + SELECT * FROM x1 + EXCEPT + SELECT * FROM x2 + LIMIT 3 +} {c d} + +finish_test From 317b7416a6e1a33446ee2fe3478ae4c13075c18b Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 26 Apr 2024 13:30:48 +0000 Subject: [PATCH 2/8] Enhance the generated_series() table-valued-function to respond to LIMIT and OFFSET. Use this to add new test cases for LIMIT and OFFSET on virtual tables in a compound SELECT. FossilOrigin-Name: 408d47ecaa3b906d0886f76a22b76339ec5878270ffe8d1838c74de09c29a33e --- ext/misc/series.c | 80 +++++++++++++++++++++++++++++++++------------ manifest | 19 +++++------ manifest.uuid | 2 +- test/tabfunc01.test | 26 +++++++++++++++ 4 files changed, 94 insertions(+), 33 deletions(-) diff --git a/ext/misc/series.c b/ext/misc/series.c index 3e859a8f23..22968854ca 100644 --- a/ext/misc/series.c +++ b/ext/misc/series.c @@ -376,13 +376,13 @@ static int seriesEof(sqlite3_vtab_cursor *cur){ ** parameter. (idxStr is not used in this implementation.) idxNum ** is a bitmask showing which constraints are available: ** -** 1: start=VALUE -** 2: stop=VALUE -** 4: step=VALUE -** -** Also, if bit 8 is set, that means that the series should be output -** in descending order rather than in ascending order. If bit 16 is -** set, then output must appear in ascending order. +** 0x01: start=VALUE +** 0x02: stop=VALUE +** 0x04: step=VALUE +** 0x08: descending order +** 0x10: ascending order +** 0x20: LIMIT VALUE +** 0x40: OFFSET VALUE ** ** This routine should initialize the cursor and position it so that it ** is pointing at the first row, or pointing off the end of the table @@ -396,17 +396,17 @@ static int seriesFilter( series_cursor *pCur = (series_cursor *)pVtabCursor; int i = 0; (void)idxStrUnused; - if( idxNum & 1 ){ + if( idxNum & 0x01 ){ pCur->ss.iBase = sqlite3_value_int64(argv[i++]); }else{ pCur->ss.iBase = 0; } - if( idxNum & 2 ){ + if( idxNum & 0x02 ){ pCur->ss.iTerm = sqlite3_value_int64(argv[i++]); }else{ pCur->ss.iTerm = 0xffffffff; } - if( idxNum & 4 ){ + if( idxNum & 0x04 ){ pCur->ss.iStep = sqlite3_value_int64(argv[i++]); if( pCur->ss.iStep==0 ){ pCur->ss.iStep = 1; @@ -416,6 +416,24 @@ static int seriesFilter( }else{ pCur->ss.iStep = 1; } + if( idxNum & 0x20 ){ + sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]); + sqlite3_int64 iTerm; + if( idxNum & 0x40 ){ + sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]); + if( iOffset>0 ){ + pCur->ss.iBase += pCur->ss.iStep*iOffset; + } + } + if( iLimit>=0 ){ + iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep; + if( pCur->ss.iStep<0 ){ + if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm; + }else{ + if( iTermss.iTerm ) pCur->ss.iTerm = iTerm; + } + } + } for(i=0; iss.isReversing = pCur->ss.iStep > 0; }else{ pCur->ss.isReversing = pCur->ss.iStep < 0; @@ -446,10 +464,13 @@ static int seriesFilter( ** ** The query plan is represented by bits in idxNum: ** -** (1) start = $value -- constraint exists -** (2) stop = $value -- constraint exists -** (4) step = $value -- constraint exists -** (8) output in descending order +** 0x01 start = $value -- constraint exists +** 0x02 stop = $value -- constraint exists +** 0x04 step = $value -- constraint exists +** 0x08 output is in descending order +** 0x10 output is in ascending order +** 0x20 LIMIT $value -- constraint exists +** 0x40 OFFSET $value -- constraint exists */ static int seriesBestIndex( sqlite3_vtab *pVTab, @@ -460,7 +481,7 @@ static int seriesBestIndex( int bStartSeen = 0; /* EQ constraint seen on the START column */ int unusableMask = 0; /* Mask of unusable constraints */ int nArg = 0; /* Number of arguments that seriesFilter() expects */ - int aIdx[3]; /* Constraints on start, stop, and step */ + int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */ const struct sqlite3_index_constraint *pConstraint; /* This implementation assumes that the start, stop, and step columns @@ -468,11 +489,22 @@ static int seriesBestIndex( assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 ); assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 ); - aIdx[0] = aIdx[1] = aIdx[2] = -1; + aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ int iCol; /* 0 for start, 1 for stop, 2 for step */ int iMask; /* bitmask for those column */ + int op = pConstraint->op; + if( op!=SQLITE_INDEX_CONSTRAINT_EQ ){ + if( op==SQLITE_INDEX_CONSTRAINT_LIMIT ){ + aIdx[3] = i; + idxNum |= 0x20; + }else if( op==SQLITE_INDEX_CONSTRAINT_OFFSET ){ + aIdx[4] = i; + idxNum |= 0x40; + } + continue; + } if( pConstraint->iColumniColumn - SERIES_COLUMN_START; assert( iCol>=0 && iCol<=2 ); @@ -486,10 +518,16 @@ static int seriesBestIndex( aIdx[iCol] = i; } } - for(i=0; i<3; i++){ + if( aIdx[3]==0 ){ + /* Ignore OFFSET if LIMIT is omitted */ + idxNum &= ~0x60; + aIdx[4] = 0; + } + for(i=0; i<5; i++){ if( (j = aIdx[i])>=0 ){ pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; + pIdxInfo->aConstraintUsage[j].omit = + !SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3; } } /* The current generate_column() implementation requires at least one @@ -517,9 +555,9 @@ static int seriesBestIndex( pIdxInfo->estimatedRows = 1000; if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn==0 ){ if( pIdxInfo->aOrderBy[0].desc ){ - idxNum |= 8; + idxNum |= 0x08; }else{ - idxNum |= 16; + idxNum |= 0x10; } pIdxInfo->orderByConsumed = 1; } diff --git a/manifest b/manifest index 5aaf6f32cc..df3495002e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\sdemonstrating\sthe\sproblem\sat\s[forum:/forumpost/c243b8f856|forum\spost\sc243b8f856].\sNo\sfix\syet. -D 2024-04-26T12:01:17.532 +C Enhance\sthe\sgenerated_series()\stable-valued-function\sto\srespond\sto\nLIMIT\sand\sOFFSET.\s\sUse\sthis\sto\sadd\snew\stest\scases\sfor\sLIMIT\sand\sOFFSET\non\svirtual\stables\sin\sa\scompound\sSELECT. +D 2024-04-26T13:30:48.724 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -411,7 +411,7 @@ F ext/misc/regexp.c 4bdd0045912f81c84908bd535ec5ad3b1c8540b4287c70ab840709636240 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 -F ext/misc/series.c 384f93a8a09cf45e1aa6575660cb580ed61d372c590aad05cdcd4a84fbd8f6ab +F ext/misc/series.c 69df6c989a37c58d831dcd4c6742ea7c98bc1517d45905290445f3bb277d2cbf F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 @@ -1679,7 +1679,7 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309 F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039 F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04 -F test/tabfunc01.test 54f27eacd054aa528a8b6e3331192c484104f30aaee351ad035f2b39a00f87c4 +F test/tabfunc01.test f150d206294471d20f50029e6b46b76b87a7a010b16dc57eb44245c76dd02802 F test/table.test 7862a00b58b5541511a26757ea9c5c7c3f8298766e98aa099deec703d9c0a8e0 F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 @@ -2186,11 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e6df846f36209bac3e420dd80ce2bbbd87ab7a20b8063fce05f78a3c7ab6027e -R 86e9e2a691d55b415e3c7d753f120811 -T *branch * vtab-limit-fix -T *sym-vtab-limit-fix * -T -sym-trunk * -U dan -Z 98d2dacd3c5e1da28914a036142cb128 +P 1685495c0a00238c9c92cce01af8108204a2fad22433ed3e7bba3c9da9ee0766 +R 5bce82b446834e1e285fe6cb5599985f +U drh +Z 002d1fa139abb35e0569e061564589d9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 80649ce5f9..9a585c8218 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1685495c0a00238c9c92cce01af8108204a2fad22433ed3e7bba3c9da9ee0766 \ No newline at end of file +408d47ecaa3b906d0886f76a22b76339ec5878270ffe8d1838c74de09c29a33e \ No newline at end of file diff --git a/test/tabfunc01.test b/test/tabfunc01.test index 8e90c549fa..3a62b81f99 100644 --- a/test/tabfunc01.test +++ b/test/tabfunc01.test @@ -322,6 +322,32 @@ ifcapable altertable { } {1 {table pragma_compile_options may not be altered}} } +#----------------------------------------------------------------------------- +# 2024-04-26 LIMIT and OFFSET passed into virtual tables +# https://sqlite.org/forum/forumpost/c243b8f856 +# +do_execsql_test tabfunc01-900 { + SELECT * FROM ( + SELECT * FROM generate_series(1,10) + UNION ALL + SELECT * FROM generate_series(101,104) + ) LIMIT 10 OFFSET 5; +} {6 7 8 9 10 101 102 103 104} +do_execsql_test tabfunc01-910 { + SELECT * FROM ( + SELECT * FROM generate_series(1,10) + UNION ALL + SELECT * FROM generate_series(101,104) + ) LIMIT -1 OFFSET 5; +} {6 7 8 9 10 101 102 103 104} +do_execsql_test tabfunc01-920 { + SELECT * FROM ( + SELECT * FROM generate_series(1,10) + UNION ALL + SELECT * FROM generate_series(101,104) + ) LIMIT -1 OFFSET 0; +} {1 2 3 4 5 6 7 8 9 10 101 102 103 104} + # Free up memory allocations intarray_addr From 99ac2324aa7f52713d4a14b29e0dde6f2c9479aa Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 26 Apr 2024 13:38:43 +0000 Subject: [PATCH 3/8] Fix handling of LIMIT and OFFSET in virtual tables that are part of a compound SELECT. FossilOrigin-Name: 40421c1c4ed5bb1ed79ad7ee37cb5a4f0b7864c1eb94abd8ee357ab2202cad30 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/whereexpr.c | 8 +++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index df3495002e..29cf2f4115 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sgenerated_series()\stable-valued-function\sto\srespond\sto\nLIMIT\sand\sOFFSET.\s\sUse\sthis\sto\sadd\snew\stest\scases\sfor\sLIMIT\sand\sOFFSET\non\svirtual\stables\sin\sa\scompound\sSELECT. -D 2024-04-26T13:30:48.724 +C Fix\shandling\sof\sLIMIT\sand\sOFFSET\sin\svirtual\stables\sthat\sare\spart\sof\na\scompound\sSELECT. +D 2024-04-26T13:38:43.836 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -839,7 +839,7 @@ F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/where.c 447d8761632fb0a18b03077161415d9713cbd0a81bf34a35cee63480e5c401c5 F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/wherecode.c 1f6940349e92a6e056aecd70163b00f331554c815c362b4cc80906c48151d73d -F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435 +F src/whereexpr.c f6c25f7c8c0301f983dbf2ca06dc0081728e3a6c104f6ffdfacd64d80c5c2e76 F src/window.c 5d95122dd330bfaebd732358c8ef067c5a9394a53ac249470d611d0ce2c52be2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -2186,8 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1685495c0a00238c9c92cce01af8108204a2fad22433ed3e7bba3c9da9ee0766 -R 5bce82b446834e1e285fe6cb5599985f +P 408d47ecaa3b906d0886f76a22b76339ec5878270ffe8d1838c74de09c29a33e +R 6c52e220da37a777a1b67496ddeb5f65 U drh -Z 002d1fa139abb35e0569e061564589d9 +Z b21bac460d0c0d27bd69b9e1b44612bb # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9a585c8218..e5ba1bb14a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -408d47ecaa3b906d0886f76a22b76339ec5878270ffe8d1838c74de09c29a33e \ No newline at end of file +40421c1c4ed5bb1ed79ad7ee37cb5a4f0b7864c1eb94abd8ee357ab2202cad30 \ No newline at end of file diff --git a/src/whereexpr.c b/src/whereexpr.c index 9d1f947a09..ff6f753b5a 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1652,9 +1652,11 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){ /* All conditions are met. Add the terms to the where-clause object. */ assert( p->pLimit->op==TK_LIMIT ); - whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, - iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); - if( p->iOffset>0 ){ + if( p->iOffset==0 || (p->selFlags & SF_Compound)==0 ){ + whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, + iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); + } + if( p->iOffset!=0 && (p->selFlags & SF_Compound)==0 ){ whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight, iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET); } From 3afd5b6d6565902271c09d6fa487e68fef3e92a4 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 26 Apr 2024 14:32:58 +0000 Subject: [PATCH 4/8] Fix a problem allowing a LIMIT constraint to be passed to a virtual table in cases where there exist WHERE terms that cannot also be passed. FossilOrigin-Name: 72c8ed9698dd2aadee7b84fd293e8306233f0fe5b5b5731687482444fdf461c7 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/whereexpr.c | 1 + test/bestindexC.test | 20 ++++++++++++++++++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 29cf2f4115..a2f90a673f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\shandling\sof\sLIMIT\sand\sOFFSET\sin\svirtual\stables\sthat\sare\spart\sof\na\scompound\sSELECT. -D 2024-04-26T13:38:43.836 +C Fix\sa\sproblem\sallowing\sa\sLIMIT\sconstraint\sto\sbe\spassed\sto\sa\svirtual\stable\sin\scases\swhere\sthere\sexist\sWHERE\sterms\sthat\scannot\salso\sbe\spassed. +D 2024-04-26T14:32:58.805 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -839,7 +839,7 @@ F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/where.c 447d8761632fb0a18b03077161415d9713cbd0a81bf34a35cee63480e5c401c5 F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/wherecode.c 1f6940349e92a6e056aecd70163b00f331554c815c362b4cc80906c48151d73d -F src/whereexpr.c f6c25f7c8c0301f983dbf2ca06dc0081728e3a6c104f6ffdfacd64d80c5c2e76 +F src/whereexpr.c e8e26dbdefa3d89c726251c8b9690ad9766ad00b92cfd11c54402e7dd1350ce7 F src/window.c 5d95122dd330bfaebd732358c8ef067c5a9394a53ac249470d611d0ce2c52be2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -936,7 +936,7 @@ F test/bestindex8.test 333ad8c6a554b885a49b68c019166eda92b05f493a92b36b0acdf7f76 F test/bestindex9.test 1a4b93db117fd8abe74ae9be982f86aa72f01e60cd4ac541e6ede39673a451a0 F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572eef44c7f F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce -F test/bestindexC.test cddef2bfebfce49f27d93de6db070e158842e9414ade05e2ddd9f869691bf698 +F test/bestindexC.test c4957155d9bd21a3e5bdd7cf32e9753b721fff7a373fdc7a8769a2a072877b7f F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc @@ -2186,8 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 408d47ecaa3b906d0886f76a22b76339ec5878270ffe8d1838c74de09c29a33e -R 6c52e220da37a777a1b67496ddeb5f65 -U drh -Z b21bac460d0c0d27bd69b9e1b44612bb +P 40421c1c4ed5bb1ed79ad7ee37cb5a4f0b7864c1eb94abd8ee357ab2202cad30 +R 2db4adc3908600896b903e9d700f2b90 +U dan +Z 2050298cecb5ad6b15cc33d4bff9b8cd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e5ba1bb14a..ba5576360c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -40421c1c4ed5bb1ed79ad7ee37cb5a4f0b7864c1eb94abd8ee357ab2202cad30 \ No newline at end of file +72c8ed9698dd2aadee7b84fd293e8306233f0fe5b5b5731687482444fdf461c7 \ No newline at end of file diff --git a/src/whereexpr.c b/src/whereexpr.c index ff6f753b5a..d25bce5f08 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1638,6 +1638,7 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){ continue; } if( pWC->a[ii].leftCursor!=iCsr ) return; + if( pWC->a[ii].prereqRight!=0 ) return; } /* Check condition (5). Return early if it is not met. */ diff --git a/test/bestindexC.test b/test/bestindexC.test index 91b8f027eb..769f1601db 100644 --- a/test/bestindexC.test +++ b/test/bestindexC.test @@ -134,4 +134,24 @@ do_execsql_test 2.1 { LIMIT 3 } {c d} +#------------------------------------------------------------------------- +reset_db +register_tcl_module db +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE y1 USING tcl(vtab_command "1 2 3 4 5 6 7 8 9 10"); +} {} + +do_execsql_test 3.1 { + SELECT * FROM y1 WHERE a = COALESCE('8', a) LIMIT 3 +} {8} + +do_execsql_test 3.2 { + SELECT * FROM y1 WHERE a = '2' LIMIT 3 +} {2} + +load_static_extension db series +do_execsql_test 3.3 { + SELECT * FROM generate_series(1, 5) WHERE value = (value & 14) LIMIT 3 +} {2 4} + finish_test From 84a231eb619f462ea183969eb29be23f5f4ecdda Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 26 Apr 2024 14:36:28 +0000 Subject: [PATCH 5/8] Use hex flag masks rather than decimals in ext/misc/series.c. FossilOrigin-Name: a94e2cd02873c283d46bf6c21d0306ad454881d7882bb167d043cc79f79a2396 --- ext/misc/series.c | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/misc/series.c b/ext/misc/series.c index 22968854ca..e355e5aab7 100644 --- a/ext/misc/series.c +++ b/ext/misc/series.c @@ -411,7 +411,7 @@ static int seriesFilter( if( pCur->ss.iStep==0 ){ pCur->ss.iStep = 1; }else if( pCur->ss.iStep<0 ){ - if( (idxNum & 16)==0 ) idxNum |= 8; + if( (idxNum & 0x10)==0 ) idxNum |= 0x08; } }else{ pCur->ss.iStep = 1; diff --git a/manifest b/manifest index a2f90a673f..6ebcff0402 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\sallowing\sa\sLIMIT\sconstraint\sto\sbe\spassed\sto\sa\svirtual\stable\sin\scases\swhere\sthere\sexist\sWHERE\sterms\sthat\scannot\salso\sbe\spassed. -D 2024-04-26T14:32:58.805 +C Use\shex\sflag\smasks\srather\sthan\sdecimals\sin\sext/misc/series.c. +D 2024-04-26T14:36:28.914 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -411,7 +411,7 @@ F ext/misc/regexp.c 4bdd0045912f81c84908bd535ec5ad3b1c8540b4287c70ab840709636240 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 -F ext/misc/series.c 69df6c989a37c58d831dcd4c6742ea7c98bc1517d45905290445f3bb277d2cbf +F ext/misc/series.c ba7c22c607e24c42bd8e6f289e246abb997e6a11b76b1a385d6f4272eae1ac88 F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 @@ -2186,8 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 40421c1c4ed5bb1ed79ad7ee37cb5a4f0b7864c1eb94abd8ee357ab2202cad30 -R 2db4adc3908600896b903e9d700f2b90 -U dan -Z 2050298cecb5ad6b15cc33d4bff9b8cd +P 72c8ed9698dd2aadee7b84fd293e8306233f0fe5b5b5731687482444fdf461c7 +R e853dfcde05ddfe7b4221b55af72f1df +U drh +Z 2da9867ae5f646560b353212baa0f0fb # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ba5576360c..bc24868c16 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -72c8ed9698dd2aadee7b84fd293e8306233f0fe5b5b5731687482444fdf461c7 \ No newline at end of file +a94e2cd02873c283d46bf6c21d0306ad454881d7882bb167d043cc79f79a2396 \ No newline at end of file From d3a4dbe4b84732a57393a1966bae5ab56460478e Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 26 Apr 2024 17:09:33 +0000 Subject: [PATCH 6/8] Further fixes and improvements to the generate_series() enhancements on this branch. FossilOrigin-Name: b7d9bd7ee2f4100608063fdf7648f290351465d393bc876a89704f643358853e --- ext/misc/series.c | 26 ++++++++++++++++++++------ manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/ext/misc/series.c b/ext/misc/series.c index e355e5aab7..0dfed181f6 100644 --- a/ext/misc/series.c +++ b/ext/misc/series.c @@ -478,7 +478,9 @@ static int seriesBestIndex( ){ int i, j; /* Loop over constraints */ int idxNum = 0; /* The query plan bitmask */ +#ifndef ZERO_ARGUMENT_GENERATE_SERIES int bStartSeen = 0; /* EQ constraint seen on the START column */ +#endif int unusableMask = 0; /* Mask of unusable constraints */ int nArg = 0; /* Number of arguments that seriesFilter() expects */ int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */ @@ -495,11 +497,16 @@ static int seriesBestIndex( int iCol; /* 0 for start, 1 for stop, 2 for step */ int iMask; /* bitmask for those column */ int op = pConstraint->op; - if( op!=SQLITE_INDEX_CONSTRAINT_EQ ){ - if( op==SQLITE_INDEX_CONSTRAINT_LIMIT ){ + if( op>=SQLITE_INDEX_CONSTRAINT_LIMIT + && op<=SQLITE_INDEX_CONSTRAINT_OFFSET + ){ + if( pConstraint->usable==0 ){ + /* do nothing */ + }else if( op==SQLITE_INDEX_CONSTRAINT_LIMIT ){ aIdx[3] = i; idxNum |= 0x20; - }else if( op==SQLITE_INDEX_CONSTRAINT_OFFSET ){ + }else{ + assert( op==SQLITE_INDEX_CONSTRAINT_OFFSET ); aIdx[4] = i; idxNum |= 0x40; } @@ -509,11 +516,15 @@ static int seriesBestIndex( iCol = pConstraint->iColumn - SERIES_COLUMN_START; assert( iCol>=0 && iCol<=2 ); iMask = 1 << iCol; - if( iCol==0 ) bStartSeen = 1; +#ifndef ZERO_ARGUMENT_GENERATE_SERIES + if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){ + bStartSeen = 1; + } +#endif if( pConstraint->usable==0 ){ unusableMask |= iMask; continue; - }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + }else if( op==SQLITE_INDEX_CONSTRAINT_EQ ){ idxNum |= iMask; aIdx[iCol] = i; } @@ -548,7 +559,7 @@ static int seriesBestIndex( ** this plan is unusable */ return SQLITE_CONSTRAINT; } - if( (idxNum & 3)==3 ){ + if( (idxNum & 0x03)==0x03 ){ /* Both start= and stop= boundaries are available. This is the ** the preferred case */ pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0)); @@ -561,6 +572,9 @@ static int seriesBestIndex( } pIdxInfo->orderByConsumed = 1; } + }else if( (idxNum & 0x21)==0x21 ){ + /* We have start= and LIMIT */ + pIdxInfo->estimatedRows = 2500; }else{ /* If either boundary is missing, we have to generate a huge span ** of numbers. Make this case very expensive so that the query diff --git a/manifest b/manifest index 6ebcff0402..8aa5658ec1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\shex\sflag\smasks\srather\sthan\sdecimals\sin\sext/misc/series.c. -D 2024-04-26T14:36:28.914 +C Further\sfixes\sand\simprovements\sto\sthe\sgenerate_series()\senhancements\son\nthis\sbranch. +D 2024-04-26T17:09:33.571 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -411,7 +411,7 @@ F ext/misc/regexp.c 4bdd0045912f81c84908bd535ec5ad3b1c8540b4287c70ab840709636240 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 -F ext/misc/series.c ba7c22c607e24c42bd8e6f289e246abb997e6a11b76b1a385d6f4272eae1ac88 +F ext/misc/series.c d96e5aac21658c6b5d54f918ac140460ec7197734c1a4fba806950831a7b1e7a F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 @@ -2186,8 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 72c8ed9698dd2aadee7b84fd293e8306233f0fe5b5b5731687482444fdf461c7 -R e853dfcde05ddfe7b4221b55af72f1df +P a94e2cd02873c283d46bf6c21d0306ad454881d7882bb167d043cc79f79a2396 +R 321007e70e23799770941a10ae3004c2 U drh -Z 2da9867ae5f646560b353212baa0f0fb +Z 725229cc9017e5eea01f2ec07aa5dfdd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bc24868c16..269ea1f24e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a94e2cd02873c283d46bf6c21d0306ad454881d7882bb167d043cc79f79a2396 \ No newline at end of file +b7d9bd7ee2f4100608063fdf7648f290351465d393bc876a89704f643358853e \ No newline at end of file From 297472a2fcae79eb2e531d8c93fdb7f36725afdb Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 26 Apr 2024 17:19:59 +0000 Subject: [PATCH 7/8] Have where.c ignore any plan from a virtual table that tries to use LIMIT/OFFSET without also using all WHERE constraints. FossilOrigin-Name: 7d30596496c6a7a37b925f13d8d94d5de224ec31bb86594fa4cc07b10082e776 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/where.c | 30 ++++++++++++++++++++++++++---- test/bestindexC.test | 8 ++++++-- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 8aa5658ec1..f0eb8e05e2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\sfixes\sand\simprovements\sto\sthe\sgenerate_series()\senhancements\son\nthis\sbranch. -D 2024-04-26T17:09:33.571 +C Have\swhere.c\signore\sany\splan\sfrom\sa\svirtual\stable\sthat\stries\sto\suse\sLIMIT/OFFSET\swithout\salso\susing\sall\sWHERE\sconstraints. +D 2024-04-26T17:19:59.258 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -836,7 +836,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c 447d8761632fb0a18b03077161415d9713cbd0a81bf34a35cee63480e5c401c5 +F src/where.c 0ef9638651b900d64d7e1e877af37cd7900159ff875547ec29b918a1497e5c9c F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/wherecode.c 1f6940349e92a6e056aecd70163b00f331554c815c362b4cc80906c48151d73d F src/whereexpr.c e8e26dbdefa3d89c726251c8b9690ad9766ad00b92cfd11c54402e7dd1350ce7 @@ -936,7 +936,7 @@ F test/bestindex8.test 333ad8c6a554b885a49b68c019166eda92b05f493a92b36b0acdf7f76 F test/bestindex9.test 1a4b93db117fd8abe74ae9be982f86aa72f01e60cd4ac541e6ede39673a451a0 F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572eef44c7f F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce -F test/bestindexC.test c4957155d9bd21a3e5bdd7cf32e9753b721fff7a373fdc7a8769a2a072877b7f +F test/bestindexC.test 6a632d3b58ffce7b9d4492c93901384d5ede891b0db76c30f90805eaccacc3bc F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc @@ -2186,8 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a94e2cd02873c283d46bf6c21d0306ad454881d7882bb167d043cc79f79a2396 -R 321007e70e23799770941a10ae3004c2 -U drh -Z 725229cc9017e5eea01f2ec07aa5dfdd +P b7d9bd7ee2f4100608063fdf7648f290351465d393bc876a89704f643358853e +R 730af36fce33d6528809ae8d9bef3e6c +U dan +Z 5c5972d6c199bce591c9d5b5a3c5a03a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 269ea1f24e..a43f8e3abf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b7d9bd7ee2f4100608063fdf7648f290351465d393bc876a89704f643358853e \ No newline at end of file +7d30596496c6a7a37b925f13d8d94d5de224ec31bb86594fa4cc07b10082e776 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 39210ddb28..820e922490 100644 --- a/src/where.c +++ b/src/where.c @@ -4057,6 +4057,21 @@ static int isLimitTerm(WhereTerm *pTerm){ && pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET; } +/* +** Return true if the first nCons constraints in the pUsage array are +** marked as in-use (have argvIndex>0). False otherwise. +*/ +static int allConstraintsUsed( + struct sqlite3_index_constraint_usage *aUsage, + int nCons +){ + int ii; + for(ii=0; iipNew->iTab. This @@ -4197,13 +4212,20 @@ static int whereLoopAddVirtualOne( *pbIn = 1; assert( (mExclude & WO_IN)==0 ); } + /* Unless pbRetryLimit is non-NULL, there should be no LIMIT/OFFSET + ** terms. And if there are any, they should follow all other terms. */ assert( pbRetryLimit || !isLimitTerm(pTerm) ); - if( isLimitTerm(pTerm) && *pbIn ){ + assert( !isLimitTerm(pTerm) || i>=nConstraint-2 ); + assert( !isLimitTerm(pTerm) || i==nConstraint-1 || isLimitTerm(pTerm+1) ); + + if( isLimitTerm(pTerm) && (*pbIn || !allConstraintsUsed(pUsage, i)) ){ /* If there is an IN(...) term handled as an == (separate call to ** xFilter for each value on the RHS of the IN) and a LIMIT or - ** OFFSET term handled as well, the plan is unusable. Set output - ** variable *pbRetryLimit to true to tell the caller to retry with - ** LIMIT and OFFSET disabled. */ + ** OFFSET term handled as well, the plan is unusable. Similarly, + ** if there is a LIMIT/OFFSET and there are other unused terms, + ** the plan cannot be used. In these cases set variable *pbRetryLimit + ** to true to tell the caller to retry with LIMIT and OFFSET + ** disabled. */ if( pIdxInfo->needToFreeIdxStr ){ sqlite3_free(pIdxInfo->idxStr); pIdxInfo->idxStr = 0; diff --git a/test/bestindexC.test b/test/bestindexC.test index 769f1601db..d854216008 100644 --- a/test/bestindexC.test +++ b/test/bestindexC.test @@ -1,4 +1,4 @@ -# 2023-10-26 +# 2024-04-26 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: @@ -13,7 +13,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -set testprefix bestindexB +set testprefix bestindexC ifcapable !vtab { finish_test @@ -154,4 +154,8 @@ do_execsql_test 3.3 { SELECT * FROM generate_series(1, 5) WHERE value = (value & 14) LIMIT 3 } {2 4} +do_execsql_test 3.4 { + SELECT value FROM generate_series(1,10) WHERE value>2 LIMIT 4 OFFSET 1; +} {4 5 6 7} + finish_test From 4c3ab545a91d50fd13e711dc250cce6927407ca2 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 26 Apr 2024 18:13:11 +0000 Subject: [PATCH 8/8] Allow virtual table implementations to handle OFFSET but not LIMIT, but not LIMIT but not OFFSET. FossilOrigin-Name: 90e5c8226a695e838e8c1703a9b8598e654d216799e8806c4d1a1f20c28c6486 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/whereexpr.c | 8 ++++---- test/bestindex8.test | 2 +- test/bestindexC.test | 23 ++++++++++++++++++++--- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index f0eb8e05e2..e044be16da 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\swhere.c\signore\sany\splan\sfrom\sa\svirtual\stable\sthat\stries\sto\suse\sLIMIT/OFFSET\swithout\salso\susing\sall\sWHERE\sconstraints. -D 2024-04-26T17:19:59.258 +C Allow\svirtual\stable\simplementations\sto\shandle\sOFFSET\sbut\snot\sLIMIT,\sbut\snot\sLIMIT\sbut\snot\sOFFSET. +D 2024-04-26T18:13:11.880 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -839,7 +839,7 @@ F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/where.c 0ef9638651b900d64d7e1e877af37cd7900159ff875547ec29b918a1497e5c9c F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/wherecode.c 1f6940349e92a6e056aecd70163b00f331554c815c362b4cc80906c48151d73d -F src/whereexpr.c e8e26dbdefa3d89c726251c8b9690ad9766ad00b92cfd11c54402e7dd1350ce7 +F src/whereexpr.c 67d15caf88a1a9528283d68ff578e024cf9fe810b517bb0343e5aaf695ad97dd F src/window.c 5d95122dd330bfaebd732358c8ef067c5a9394a53ac249470d611d0ce2c52be2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -932,11 +932,11 @@ F test/bestindex4.test 3039894f2dad50f3a68443dffad1b44c9b067ac03870102df1ce3d9a4 F test/bestindex5.test a0c90b2dad7836e80a01379e200e5f8ec9476d49b349af02c0dbff2fb75dc98d F test/bestindex6.test 16942535b551273f3ad9df8d7cc4b7f22b1fcd8882714358859eb049a6f99dd4 F test/bestindex7.test f094c669a6400777f4d2ddc3ed28e39169f1adb5be3d59b55f22ccf8c414b71e -F test/bestindex8.test 333ad8c6a554b885a49b68c019166eda92b05f493a92b36b0acdf7f766d04dad +F test/bestindex8.test b63a4f171a2c83d481bb14c431a8b72e85d27b2ffdaa0435a95d58ca941678f9 F test/bestindex9.test 1a4b93db117fd8abe74ae9be982f86aa72f01e60cd4ac541e6ede39673a451a0 F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572eef44c7f F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce -F test/bestindexC.test 6a632d3b58ffce7b9d4492c93901384d5ede891b0db76c30f90805eaccacc3bc +F test/bestindexC.test c14a8c8639b6825b0efa1ae693f34ec04f41a46e3056e7063d6e0f46bf4ff692 F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc @@ -2186,8 +2186,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b7d9bd7ee2f4100608063fdf7648f290351465d393bc876a89704f643358853e -R 730af36fce33d6528809ae8d9bef3e6c +P 7d30596496c6a7a37b925f13d8d94d5de224ec31bb86594fa4cc07b10082e776 +R 9eed5aaa8e26bff88d62db6ed7adfa29 U dan -Z 5c5972d6c199bce591c9d5b5a3c5a03a +Z d168d9476b0b5c157ebfbc91beb1e6fe # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a43f8e3abf..3d3eb37fa7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7d30596496c6a7a37b925f13d8d94d5de224ec31bb86594fa4cc07b10082e776 \ No newline at end of file +90e5c8226a695e838e8c1703a9b8598e654d216799e8806c4d1a1f20c28c6486 \ No newline at end of file diff --git a/src/whereexpr.c b/src/whereexpr.c index d25bce5f08..5465dc953b 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1653,14 +1653,14 @@ void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){ /* All conditions are met. Add the terms to the where-clause object. */ assert( p->pLimit->op==TK_LIMIT ); - if( p->iOffset==0 || (p->selFlags & SF_Compound)==0 ){ - whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, - iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); - } if( p->iOffset!=0 && (p->selFlags & SF_Compound)==0 ){ whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight, iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET); } + if( p->iOffset==0 || (p->selFlags & SF_Compound)==0 ){ + whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, + iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); + } } } diff --git a/test/bestindex8.test b/test/bestindex8.test index e95c3c6dc2..3ed7f6703e 100644 --- a/test/bestindex8.test +++ b/test/bestindex8.test @@ -158,7 +158,7 @@ do_test 2.2 { set ::lFilterArgs [list] execsql { SELECT * FROM vt1 LIMIT 5 OFFSET 50 } set ::lFilterArgs -} {{5 50}} +} {{50 5}} do_test 2.3 { set ::lFilterArgs [list] diff --git a/test/bestindexC.test b/test/bestindexC.test index d854216008..476ea39faa 100644 --- a/test/bestindexC.test +++ b/test/bestindexC.test @@ -40,11 +40,11 @@ proc vtab_command {lVal method args} { foreach c $clist { array set a $c if {$a(usable)==0} continue - if {$a(op)=="limit"} { + if {$a(op)=="limit" && ![info exists ::do_not_use_limit]} { lappend idxstr limit lappend res omit $idx } - if {$a(op)=="offset"} { + if {$a(op)=="offset" && ![info exists ::do_not_use_offset]} { lappend idxstr offset lappend res omit $idx } @@ -58,9 +58,13 @@ proc vtab_command {lVal method args} { set idxstr [lindex $args 1] set LIMIT "" foreach a $idxstr b [lindex $args 2] { - append LIMIT " $a $b" + set x($a) $b } + if {![info exists x(limit)]} { set x(limit) -1 } + if {![info exists x(offset)]} { set x(offset) -1 } + set LIMIT " LIMIT $x(limit) OFFSET $x(offset)" + set idx 1 foreach v $lVal { lappend lRow "($idx, '$v')" @@ -158,4 +162,17 @@ do_execsql_test 3.4 { SELECT value FROM generate_series(1,10) WHERE value>2 LIMIT 4 OFFSET 1; } {4 5 6 7} +set ::do_not_use_limit 1 +do_execsql_test 3.5 { + SELECT * FROM y1 LIMIT 5 OFFSET 3 +} {4 5 6 7 8} +unset ::do_not_use_limit +set ::do_not_use_offset 1 +do_execsql_test 3.6 { + SELECT * FROM y1 LIMIT 5 OFFSET 3 +} {4 5 6 7 8} +unset ::do_not_use_offset + + + finish_test