0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2025-03-16 09:41:04 +00:00

Fix for 2a5629202f. When considering whether or not a UNIQUE index may be used to optimize an ORDER BY clause, do not assume that all index entries are distinct unless there is some reason to believe that the index contains no NULL values.

FossilOrigin-Name: 9870e4c4fef10112c987c40cb1b95255a7214202
This commit is contained in:
dan
2012-04-20 15:24:53 +00:00
parent 50f79f56a8
commit 99f8fb66a4
5 changed files with 105 additions and 19 deletions

@ -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

@ -1 +1 @@
372a90e2264a29ce543c093766cdec764d18b5a5
9870e4c4fef10112c987c40cb1b95255a7214202

@ -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; i<pIdx->nColumn; i++){
if( aCol[pIdx->aiColumn[i]].notNull==0 ) break;
}
return (i>=pIdx->nColumn);
}
return 0;
}

71
test/tkt-2a5629202f.test Normal file

@ -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

@ -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