Compare commits

...

2 Commits

Author SHA1 Message Date
drh 0d86c10db3 Added test cases based on Bruce Momjian's talk on SQL NULLs.
FossilOrigin-Name: 68c168b5e57aebc1ffd79006068aa99e78b59ee0
2015-06-13 19:05:44 +00:00
drh 03a06ac302 Add the IS DISTINCT FROM and IS NOT DISTINCT FROM operators.
FossilOrigin-Name: 0be4478209fc3544152874fde2750ce86b410221
2015-06-13 11:48:52 +00:00
4 changed files with 280 additions and 8 deletions
+7 -7
View File
@@ -1,5 +1,5 @@
C Omit\smutex\scalls\sin\spcache1\swhen\sthe\smutex\sis\sNULL,\sfor\sa\ssignificant\nperformance\simprovement.
D 2015-06-13T11:19:47.811
C Added\stest\scases\sbased\son\sBruce\sMomjian's\stalk\son\sSQL\sNULLs.
D 2015-06-13T19:05:44.010
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -239,7 +239,7 @@ F src/os_win.c 27cc135e2d0b8b1e2e4944db1e2669a6a18fa0f8
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
F src/pager.c 9bc918a009285f96ec6dac62dd764c7063552455
F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77
F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8
F src/parse.y d3388f709c7c03d45d375dd5fb89e54256406143
F src/pcache.c 10539fb959849ad6efff80050541cab3d25089d4
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
F src/pcache1.c 7ca0caf7ec16c365aff3ddb4a7e00734a0e1fe97
@@ -787,6 +787,7 @@ F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
F test/momjian1.test 81eb75ee46a4385be922b0e6af52d936213cb22e
F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
@@ -1286,8 +1287,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 2e8ad2ead9d146e312c693d9b967bbd5b92429d9 dcf4fb8d764611de60afea27cda0a8548ba7ca82
R caec30587447e9722ed3cdf5357476d2
T +closed dcf4fb8d764611de60afea27cda0a8548ba7ca82
P 0be4478209fc3544152874fde2750ce86b410221
R aa34463b472eb51d91292ad6ef6dc49a
U drh
Z d83dc113d9069d701eaef24905e6fe62
Z e68b43ce2d2a7b57cd7747d8f8290458
+1 -1
View File
@@ -1 +1 @@
caf8f574e5c64da461c6dfba8a06cf3fb18aaa42
68c168b5e57aebc1ffd79006068aa99e78b59ee0
+10
View File
@@ -991,6 +991,8 @@ expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
// expr1 IS expr2
// expr1 IS NOT expr2
// expr1 IS DISTINCT FROM expr2
// expr1 IS NOT DISTINCT FROM expr2
//
// If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2
// is any other expression, code as TK_IS or TK_ISNOT.
@@ -1003,6 +1005,14 @@ expr(A) ::= expr(X) IS NOT expr(Y). {
spanBinaryExpr(&A,pParse,TK_ISNOT,&X,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL);
}
expr(A) ::= expr(X) IS DISTINCT FROM expr(Y). {
spanBinaryExpr(&A,pParse,TK_ISNOT,&X,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL);
}
expr(A) ::= expr(X) IS NOT DISTINCT FROM expr(Y). {
spanBinaryExpr(&A,pParse,TK_IS,&X,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_ISNULL);
}
%include {
/* Construct an expression node for a unary prefix operator
+262
View File
@@ -0,0 +1,262 @@
# 2015-06-12
#
# 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 derived from Bruce Momjian's talk on NULL handling in SQL.
# http://momjian.us/main/writings/pgsql/nulls.pdf
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db null nil
do_execsql_test momjian1-100 {
SELECT null;
} {nil}
do_execsql_test momjian1-110 {
CREATE TABLE nulltest (x INTEGER, y INTEGER);
INSERT INTO nulltest VALUES (1,NULL);
SELECT * FROM nulltest;
} {1 nil}
do_execsql_test momjian1-120 {
INSERT INTO nulltest (x) VALUES (2);
SELECT * FROM nulltest;
} {1 nil 2 nil}
do_catchsql_test momjian1-130 {
CREATE TABLE nulltest2 (x INTEGER NOT NULL, y INTEGER NOT NULL);
INSERT INTO nulltest2 VALUES (3,NULL )
} {1 {NOT NULL constraint failed: nulltest2.y}}
do_catchsql_test momjian1-131 {
INSERT INTO nulltest2 (x) VALUES (4);
} {1 {NOT NULL constraint failed: nulltest2.y}}
do_execsql_test momjian1-140 {
SELECT NULL+1;
} {nil}
do_execsql_test momjian1-141 {
SELECT NULL || 'a';
} {nil}
do_execsql_test momjian1-142 {
SELECT 'b' || NULL;
} {nil}
do_execsql_test momjian1-150 {
CREATE TABLE inctest (x INTEGER);
INSERT INTO inctest VALUES (30), (40),(NULL);
SELECT x + 1 FROM inctest;
} {31 41 nil}
do_execsql_test momjian1-160 {
SELECT NULL = 1;
} {nil}
do_execsql_test momjian1-161 {
SELECT NULL = '';
} {nil}
do_execsql_test momjian1-162 {
SELECT NULL = NULL;
} {nil}
do_execsql_test momjian1-163 {
SELECT NULL < NULL + 1;
} {nil}
do_execsql_test momjian1-170 {
SELECT 1 WHERE 1;
} {1}
do_execsql_test momjian1-171 {
SELECT 1 WHERE 0;
} {}
do_execsql_test momjian1-172 {
SELECT 1 WHERE NULL;
} {}
do_execsql_test momjian1-180 {
SELECT 1 AND NULL;
} {nil}
do_execsql_test momjian1-181 {
SELECT NOT NULL;
} {nil}
do_execsql_test momjian1-190 {
SELECT * FROM inctest WHERE x >= 0;
} {30 40}
do_execsql_test momjian1-191 {
SELECT * FROM inctest WHERE x < 0;
} {}
do_execsql_test momjian1-192 {
SELECT * FROM inctest WHERE x < 0 OR x >= 0;
} {30 40}
do_execsql_test momjian1-200 {
SELECT * FROM inctest WHERE x <> 10;
} {30 40}
do_execsql_test momjian1-201 {
SELECT * FROM inctest WHERE x <> 10 OR x = 10;
} {30 40}
do_execsql_test momjian1-210 {
SELECT 1 <> 2 AND 1 <> 3;
} {1}
do_execsql_test momjian1-211 {
SELECT 1 <> 2 AND 1 <> 3 AND 1 <> NULL;
} {nil}
do_execsql_test momjian1-220 {
SELECT 'a' IN (SELECT NULL);
} {nil}
do_execsql_test momjian1-221 {
SELECT 'a' NOT IN (SELECT NULL);
} {nil}
do_execsql_test momjian1-230 {
SELECT 'a' IN (SELECT 'a' UNION ALL SELECT NULL);
} {1}
do_execsql_test momjian1-231 {
SELECT 'a' NOT IN (SELECT 'a' UNION ALL SELECT NULL);
} {0}
do_execsql_test momjian1-232 {
SELECT 'a' IN (SELECT 'b' UNION ALL SELECT NULL);
} {nil}
do_execsql_test momjian1-233 {
SELECT 'a' NOT IN (SELECT 'b' UNION ALL SELECT NULL);
} {nil}
do_execsql_test momjian1-240 {
SELECT 'a' = 'b' OR 'a' = NULL;
} {nil}
do_execsql_test momjian1-241 {
SELECT 'a' <> 'b' AND 'a' <> NULL;
} {nil}
do_execsql_test momjian1-250 {
SELECT NULL = NULL;
} {nil}
do_execsql_test momjian1-251 {
SELECT NULL IS NULL;
} {1}
do_execsql_test momjian1-252 {
SELECT NULL IS NOT NULL;
} {0}
do_execsql_test momjian1-260 {
SELECT * FROM inctest WHERE x IS NULL;
} {nil}
do_execsql_test momjian1-261 {
SELECT * FROM inctest WHERE x IS NOT NULL;
} {30 40}
do_execsql_test momjian1-270 {
SELECT 2 IS DISTINCT FROM 1;
SELECT 2 IS NOT 1
} {1 1}
do_execsql_test momjian1-271 {
SELECT NULL IS DISTINCT FROM 1;
SELECT NULL IS NOT 1;
} {1 1}
do_execsql_test momjian1-272 {
SELECT NULL IS DISTINCT FROM NULL;
SELECT NULL IS NOT NULL;
} {0 0}
do_execsql_test momjian1-273 {
SELECT NULL <> 1;
} {nil}
do_execsql_test momjian1-280 {
-- SELECT * FROM inctest WHERE x IS DISTINCT FROM 30;
SELECT * FROM inctest WHERE x IS NOT 30;
} {40 nil}
do_execsql_test momjian1-281 {
-- SELECT * FROM inctest WHERE x IS NOT DISTINCT FROM 30;
SELECT * FROM inctest WHERE x IS 30;
} {30}
do_execsql_test momjian1-300 {
CREATE TABLE disttest (x INTEGER, y INTEGER);
INSERT INTO disttest VALUES (1, 1), (2, 3), (NULL, NULL);
SELECT * FROM disttest where x IS NOT DISTINCT FROM y;
SELECT * FROM disttest WHERE x IS y;
} {1 1 nil nil 1 1 nil nil}
do_execsql_test momjian1-310 {
WITH ordertest AS (
SELECT NULL
UNION ALL
SELECT 2
UNION ALL
SELECT 1
UNION ALL
SELECT NULL
)
SELECT * FROM ordertest
ORDER BY 1;
} {nil nil 1 2}
do_execsql_test momjian1-320 {
CREATE TABLE uniqtest (x INTEGER);
CREATE UNIQUE INDEX i_uniqtest ON uniqtest (x);
INSERT INTO uniqtest VALUES (1),(NULL), (NULL);
SELECT * FROM uniqtest;
} {1 nil nil}
do_execsql_test momjian1-330 {
CREATE TABLE aggtest (x INTEGER);
INSERT INTO aggtest VALUES (7), (8), (NULL);
SELECT COUNT(*), COUNT(x), SUM(x), MIN(x), MAX(x), AVG(x) FROM aggtest;
} {3 2 15 7 8 7.5}
do_execsql_test momjian1-331 {
DELETE FROM aggtest;
SELECT COUNT(*), COUNT(x), SUM(x), MIN(x), MAX(x), AVG(x) FROM aggtest;
} {0 0 nil nil nil nil}
do_execsql_test momjian1-340 {
DELETE FROM aggtest;
INSERT INTO aggtest VALUES (7), (8), (NULL), (NULL);
SELECT x, COUNT(*), COUNT(x), SUM(x), MIN(x), MAX(x), AVG(x)
FROM aggtest
GROUP BY x ORDER BY x;
} {nil 2 0 nil nil nil nil 7 1 1 7 7 7 7.0 8 1 1 8 8 8 8.0}
do_execsql_test momjian1-350 {
SELECT COALESCE(NULL, 0);
} {0}
do_execsql_test momjian1-351 {
SELECT COALESCE(NULL, 'I am null.');
} {{I am null.}}
do_execsql_test momjian1-352 {
CREATE TABLE nullmaptest(x TEXT);
INSERT INTO nullmaptest VALUES ('f'), ('g'), (NULL);
SELECT x, COALESCE(x, 'n/a') FROM nullmaptest;
} {f f g g nil n/a}
do_execsql_test momjian1-353 {
SELECT 'a' || COALESCE(NULL, '') || 'b';
} {ab}
do_execsql_test momjian1-354 {
SELECT SUM(x), COALESCE(SUM(x), 0) FROM aggtest;
} {15 15}
do_execsql_test momjian1-355 {
DELETE FROM aggtest;
SELECT SUM(x), COALESCE(SUM(x), 0) FROM aggtest;
} {nil 0}
do_execsql_test momjian1-360 {
CREATE TABLE emptytest (x INTEGER);
SELECT * from emptytest;
} {}
do_execsql_test momjian1-361 {
SELECT (SELECT * from emptytest);
} {nil}
do_execsql_test momjian1-362 {
SELECT (SELECT * from emptytest) IS NULL;
} {1}
finish_test