diff --git a/manifest b/manifest index f029544c0d..700e725777 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sobsolete\sart. -D 2012-04-20T12:02:32.039 +C Fix\sfor\s2a5629202f.\sWhen\sconsidering\swhether\sor\snot\sa\sUNIQUE\sindex\smay\sbe\sused\sto\soptimize\san\sORDER\sBY\sclause,\sdo\snot\sassume\sthat\sall\sindex\sentries\sare\sdistinct\sunless\sthere\sis\ssome\sreason\sto\sbelieve\sthat\sthe\sindex\scontains\sno\sNULL\svalues. +D 2012-04-20T15:24:53.110 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -246,7 +246,7 @@ F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847 F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 2112422a404dcca5d47f6630bdf180bccd36c62b +F src/where.c e25ae482e94226df7f95fa4e0545cc7064e86574 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 @@ -733,6 +733,7 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 +F test/tkt-2a5629202f.test 1ab32e084e9fc3d36be6dee2617530846a0eb0b6 F test/tkt-2d1a5c67d.test b028a811049eb472cb2d3a43fc8ce4f6894eebda F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 1f714c14b6682c5db715e0bda347926a3456f7a9 @@ -931,7 +932,7 @@ F test/walro.test e6bb27762c9f22601cbb8bff6e0acfd124e74b63 F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test a2ed5270eb695284d4ad27d252517bdc3317ee2a -F test/where.test de337a3fe0a459ec7c93db16a519657a90552330 +F test/where.test 4c9f69987ed2aa0173fa930f2b41ab9879478cd8 F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554 F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 @@ -992,7 +993,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 3281972eaa46cb57fd9f0387063f47430dc0a3b4 -R 996fa506825219f1b7ce0687d37d97d8 -U drh -Z 27a58991babc71a559ca9c653e33aa72 +P 372a90e2264a29ce543c093766cdec764d18b5a5 +R c55b0e9d6060c081eba144f695f549a1 +U dan +Z 3f4edf7c59f1f66ed37303deb846aef3 diff --git a/manifest.uuid b/manifest.uuid index 19174a46d2..c191b9349f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -372a90e2264a29ce543c093766cdec764d18b5a5 \ No newline at end of file +9870e4c4fef10112c987c40cb1b95255a7214202 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 5471f71dcf..f2c180959b 100644 --- a/src/where.c +++ b/src/where.c @@ -1718,14 +1718,26 @@ static int isSortingIndex( } if( pIdx->onError!=OE_None && i==pIdx->nColumn && (wsFlags & WHERE_COLUMN_NULL)==0 - && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ - /* All terms of this index match some prefix of the ORDER BY clause - ** and the index is UNIQUE and no terms on the tail of the ORDER BY - ** clause reference other tables in a join. If this is all true then - ** the order by clause is superfluous. Not that if the matching - ** condition is IS NULL then the result is not necessarily unique - ** even on a UNIQUE index, so disallow those cases. */ - return 1; + && !referencesOtherTables(pOrderBy, pMaskSet, j, base) + ){ + Column *aCol = pIdx->pTable->aCol; + int i; + + /* All terms of this index match some prefix of the ORDER BY clause, + ** the index is UNIQUE, and no terms on the tail of the ORDER BY + ** refer to other tables in a join. So, assuming that the index entries + ** visited contain no NULL values, then this index delivers rows in + ** the required order. + ** + ** It is not possible for any of the first nEqCol index fields to be + ** NULL (since the corresponding "=" operator in the WHERE clause would + ** not be true). So if all remaining index columns have NOT NULL + ** constaints attached to them, we can be confident that the visited + ** index entries are free of NULLs. */ + for(i=nEqCol; inColumn; i++){ + if( aCol[pIdx->aiColumn[i]].notNull==0 ) break; + } + return (i>=pIdx->nColumn); } return 0; } diff --git a/test/tkt-2a5629202f.test b/test/tkt-2a5629202f.test new file mode 100644 index 0000000000..037f100f65 --- /dev/null +++ b/test/tkt-2a5629202f.test @@ -0,0 +1,71 @@ +# 2012 April 19 +# +# 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. +# +#*********************************************************************** +# The tests in this file were used while developing the SQLite 4 code. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-2a5629202f + +# This procedure executes the SQL. Then it checks to see if the OP_Sort +# opcode was executed. If an OP_Sort did occur, then "sort" is appended +# to the result. If no OP_Sort happened, then "nosort" is appended. +# +# This procedure is used to check to make sure sorting is or is not +# occurring as expected. +# +proc cksort {sql} { + set data [execsql $sql] + if {[db status sort]} {set x sort} {set x nosort} + lappend data $x + return $data +} + +do_execsql_test 1.1 { + CREATE TABLE t8(b TEXT, c TEXT); + INSERT INTO t8 VALUES('a', 'one'); + INSERT INTO t8 VALUES('b', 'two'); + INSERT INTO t8 VALUES(NULL, 'three'); + INSERT INTO t8 VALUES(NULL, 'four'); +} + +do_execsql_test 1.2 { + SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c +} {null/four null/three a/one b/two} + +do_execsql_test 1.3 { + CREATE UNIQUE INDEX i1 ON t8(b); + SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c +} {null/four null/three a/one b/two} + +#------------------------------------------------------------------------- +# + +do_execsql_test 2.1 { + CREATE TABLE t2(a, b NOT NULL, c); + CREATE UNIQUE INDEX t2ab ON t2(a, b); + CREATE UNIQUE INDEX t2ba ON t2(b, a); +} + +do_test 2.2 { + cksort { SELECT * FROM t2 WHERE a = 10 ORDER BY a, b, c } +} {nosort} + +do_test 2.3 { + cksort { SELECT * FROM t2 WHERE b = 10 ORDER BY a, b, c } +} {sort} + +do_test 2.4 { + cksort { SELECT * FROM t2 WHERE a IS NULL ORDER BY a, b, c } +} {sort} + +finish_test + diff --git a/test/where.test b/test/where.test index 9145bcc753..3826a5f64a 100644 --- a/test/where.test +++ b/test/where.test @@ -1105,15 +1105,17 @@ do_test where-14.4 { } } {1/1 1/4 4/1 4/4 nosort} do_test where-14.5 { + # This test case changed from "nosort" to "sort". See ticket 2a5629202f. cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.b, x.a||x.b } -} {4/1 4/4 1/1 1/4 nosort} +} {4/1 4/4 1/1 1/4 sort} do_test where-14.6 { + # This test case changed from "nosort" to "sort". See ticket 2a5629202f. cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.b, x.a||x.b DESC } -} {4/1 4/4 1/1 1/4 nosort} +} {4/1 4/4 1/1 1/4 sort} do_test where-14.7 { cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.b, y.a||y.b