#!/usr/bin/env tclsh set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test select-const-1 { SELECT 1 } {1} do_execsql_test select-const-2 { SELECT 2 } {2} do_execsql_test select-const-3 { SELECT 0xDEAF } {57007} do_execsql_test select-const-4 { SELECT -0xA } {-10} do_execsql_test select-true { SELECT true } {1} do_execsql_test select-false { SELECT false } {0} do_execsql_test select-text-escape-1 { SELECT '''a' } {'a} do_execsql_test select-blob-empty { SELECT x''; } {} do_execsql_test select-blob-ascii { SELECT x'6C696D626F'; } {limbo} do_execsql_test select-blob-emoji { SELECT x'F09FA680'; } {🦀} do_execsql_test select-limit-0 { SELECT id FROM users LIMIT 0; } {} do_execsql_test select-doubly-qualified { SELECT main.users.id FROM users LIMIT 0; } {} do_execsql_test_error select-doubly-qualified-wrong-table { SELECT main.wrong.id FROM users LIMIT 0; } {.*} do_execsql_test_error select-doubly-qualified-wrong-column { SELECT main.users.wrong FROM users LIMIT 0; } {.*} do_execsql_test select-limit-expression { select price from products limit 2 + 1 - 1; } {79.0 82.0} # ORDER BY id here because sqlite uses age_idx here and we (yet) don't so force it to evaluate in ID order do_execsql_test select-limit-true { SELECT id FROM users ORDER BY id LIMIT true; } {1} do_execsql_test select-limit-false { SELECT id FROM users ORDER BY id LIMIT false; } {} do_execsql_test realify { select price from products limit 1; } {79.0} do_execsql_test select-add { select u.age + 1 from users u where u.age = 91 limit 1; } {92} do_execsql_test select-subtract { select u.age - 1 from users u where u.age = 91 limit 1; } {90} do_execsql_test case-insensitive-columns { select u.aGe + 1 from USERS u where U.AGe = 91 limit 1; } {92} do_execsql_test table-star { select p.*, p.name from products p limit 1; } {1|hat|79.0|hat} do_execsql_test table-star-2 { select p.*, u.first_name from users u join products p on u.id = p.id limit 1; } {1|hat|79.0|Jamie} do_execsql_test select_with_quoting { select `users`.id from [users] where users.[id] = 5; } {5} do_execsql_test select_with_quoting_2 { select "users".`id` from users where `users`.[id] = 5; } {5} do_execsql_test select-rowid { select rowid, first_name from users u where rowid = 5; } {5|Edward} do_execsql_test select-rowid-2 { select u.rowid, first_name from users u where rowid = 5; } {5|Edward} do_execsql_test seekrowid { select * from users u where u.id = 5; } {"5|Edward|Miller|christiankramer@example.com|725-281-1033|08522 English Plain|Lake Keith|ID|23283|15"} do_execsql_test select_parenthesized { select (price + 100) from products limit 1; } {179.0} do_execsql_test select_case_base_else { select case when 0 then 'false' when 1 then 'true' else 'null' end; } {true} do_execsql_test select_case_noelse_null { select case when 0 then 0 end; } {} do_execsql_test select_base_case_else { select case 1 when 0 then 'zero' when 1 then 'one' else 'two' end; } {one} do_execsql_test select_base_case_null_result { select case NULL when 0 then 'first' else 'second' end; select case NULL when NULL then 'first' else 'second' end; select case 0 when 0 then 'first' else 'second' end; } {second second first} do_execsql_test select_base_case_noelse_null { select case 'null else' when 0 then 0 when 1 then 1 end; } {} do_execsql_test select-is-null { select null is null, (1 / 0) is null, null is (1 / 0), (1 / 0) is (1 / 0); select 4 is null, '4' is null, 0 is null, (1 / 2) is null; } {1|1|1|1 0|0|0|0} do_execsql_test select-is-not-null { select null is not null, (1 / 0) is not null, null is not (1 / 0), (1 / 0) is not (1 / 0); select 4 is not null, '4' is not null, 0 is not null, (1 / 2) is not null; } {0|0|0|0 1|1|1|1} do_execsql_test select_bin_shr { select 997623670 >> 0, 997623670 >> 1, 997623670 >> 10, 997623670 >> 30; select -997623670 >> 0, -997623670 >> 1, -997623670 >> 10, -997623670 >> 30; select 997623670 << 0, 997623670 << -1, 997623670 << -10, 997623670 << -30; select -997623670 << 0, -997623670 << -1, -997623670 << -10, -997623670 << -30; } {997623670|498811835|974241|0 -997623670|-498811835|-974242|-1 997623670|498811835|974241|0 -997623670|-498811835|-974242|-1} do_execsql_test select_bin_shl { select 997623670 << 0, 997623670 << 1, 997623670 << 10, 997623670 << 30; select -997623670 << 0, -997623670 << 1, -997623670 << 10, -997623670 << 30; select 997623670 >> 0, 997623670 >> -1, 997623670 >> -10, 997623670 >> -30; select -997623670 >> 0, -997623670 >> -1, -997623670 >> -10, -997623670 >> -30; } {997623670|1995247340|1021566638080|1071190259091374080 -997623670|-1995247340|-1021566638080|-1071190259091374080 997623670|1995247340|1021566638080|1071190259091374080 -997623670|-1995247340|-1021566638080|-1071190259091374080} # Test LIKE in SELECT position do_execsql_test select-like-expression { select 'bar' like 'bar%' } {1} do_execsql_test select-not-like-expression { select 'bar' not like 'bar%' } {0} # regression test for float divisor being cast to zero int and panicking do_execsql_test select-like-expression { select 2 % 0.5 } {} do_execsql_test select_positive_infinite_float { SELECT 1.7976931348623157E+308 + 1e308; -- f64::MAX + 1e308 } {Inf} do_execsql_test select_negative_infinite_float { SELECT -1.7976931348623157E+308 - 1e308 -- f64::MIN - 1e308 } {-Inf} do_execsql_test select_shl_large_negative_float { SELECT 1 << -1e19; SELECT 1 << -9223372036854775808; -- i64::MIN SELECT 1 << 9223372036854775807; -- i64::MAX } {0 0 0} do_execsql_test select_shl_basic { SELECT 1 << 0, 1 << 1, 1 << 2, 1 << 3; SELECT 2 << 0, 2 << 1, 2 << 2, 2 << 3; } {1|2|4|8 2|4|8|16} do_execsql_test select_shl_negative_numbers { SELECT -1 << 0, -1 << 1, -1 << 2, -1 << 3; SELECT -2 << 0, -2 << 1, -2 << 2, -2 << 3; } {-1|-2|-4|-8 -2|-4|-8|-16} do_execsql_test select_shl_negative_shifts { SELECT 8 << -1, 8 << -2, 8 << -3, 8 << -4; SELECT -8 << -1, -8 << -2, -8 << -3, -8 << -4; } {4|2|1|0 -4|-2|-1|-1} do_execsql_test select_shl_large_shifts { SELECT 1 << 62, 1 << 63, 1 << 64; SELECT -1 << 62, -1 << 63, -1 << 64; } {4611686018427387904|-9223372036854775808|0 -4611686018427387904|-9223372036854775808|0} do_execsql_test select_shl_text_conversion { SELECT '1' << '2'; SELECT '8' << '-2'; SELECT '-4' << '2'; } {4 2 -16} do_execsql_test select_shl_chained { SELECT (1 << 2) << 3; SELECT (2 << 1) << (1 << 1); } {32 16} do_execsql_test select_shl_numeric_types { SELECT CAST(1 AS INTEGER) << 2; SELECT 1.0 << 2; SELECT 1.5 << 2; } {4 4 4} do_execsql_test select_fuzz_failure_case { SELECT (-9 << ((-6) << (9)) >> ((5)) % -10 - + - (-9)); } {-16} # regression test for https://github.com/tursodatabase/turso/issues/1157 do_execsql_test select-invalid-numeric-text { select -'e'; } {0} do_execsql_test select-invalid-numeric-text { select -'E'; } {0} do_execsql_test_on_specific_db {:memory:} select-union-all-1 { CREATE TABLE t1 (x INTEGER); CREATE TABLE t2 (x INTEGER); CREATE TABLE t3 (x INTEGER); INSERT INTO t1 VALUES(1),(2),(3); INSERT INTO t2 VALUES(4),(5),(6); INSERT INTO t3 VALUES(7),(8),(9); SELECT x FROM t1 UNION ALL SELECT x FROM t2 UNION ALL SELECT x FROM t3; } {1 2 3 4 5 6 7 8 9} do_execsql_test_on_specific_db {:memory:} select-union-all-with-filters { CREATE TABLE t4 (x INTEGER); CREATE TABLE t5 (x INTEGER); CREATE TABLE t6 (x INTEGER); INSERT INTO t4 VALUES(1),(2),(3),(4); INSERT INTO t5 VALUES(5),(6),(7),(8); INSERT INTO t6 VALUES(9),(10),(11),(12); SELECT x FROM t4 WHERE x > 2 UNION ALL SELECT x FROM t5 WHERE x < 7 UNION ALL SELECT x FROM t6 WHERE x = 10; } {3 4 5 6 10} do_execsql_test_error select-star-no-from { SELECT *; } {no tables specified} do_execsql_test_error select-star-and-constant-no-from { SELECT *, 1; } {no tables specified} do_execsql_test_error select-star-subquery { SELECT 1 FROM (SELECT *); } {no tables specified} do_execsql_test_on_specific_db {:memory:} select-union-1 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); select * from t UNION select * from u; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-all-union { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t UNION select * from u UNION ALL select * from v; } {x|x y|y x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-all-union-2 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t UNION ALL select * from u UNION select * from v; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-3 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t UNION select * from u UNION select * from v; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-4 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t UNION select * from u UNION select * from v UNION select * from t; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-all-union-3 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t UNION select * from u UNION select * from v UNION ALL select * from t; } {x|x y|y x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-all-with-offset { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'),('z', 'z'); select * from t UNION ALL select * from u limit 1 offset 1; } {y|y} do_execsql_test_on_specific_db {:memory:} select-union-with-offset { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'),('z', 'z'); select * from t UNION select * from u limit 1 offset 1; } {y|y} do_execsql_test_on_specific_db {:memory:} select-intersect-1 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); select * from t INTERSECT select * from u; } {x|x} do_execsql_test_on_specific_db {:memory:} select-intersect-2 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); INSERT INTO v VALUES('a','x'),('y','y'); select * from t INTERSECT select * from u INTERSECT select * from v INTERSECT select * from t; } {y|y} do_execsql_test_on_specific_db {:memory:} select-intersect-union { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t INTERSECT select * from u UNION select * from v; } {x|x z|z} do_execsql_test_on_specific_db {:memory:} select-union-intersect { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t UNION select * from u INTERSECT select * from v; } {x|x} do_execsql_test_on_specific_db {:memory:} select-union-all-intersect { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t UNION ALL select * from u INTERSECT select * from v; } {x|x} do_execsql_test_on_specific_db {:memory:} select-intersect-union-all { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t INTERSECT select * from u UNION ALL select * from v; } {x|x x|x z|z} do_execsql_test_on_specific_db {:memory:} select-intersect-with-limit { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'), ('z','z'); INSERT INTO u VALUES('x','x'),('y','y'), ('z','z'); select * from t INTERSECT select * from u limit 2; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-intersect-with-offset { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'), ('z','z'); INSERT INTO u VALUES('x','x'),('y','y'), ('z','z'); select * from t INTERSECT select * from u limit 2 offset 1; } {y|y z|z} do_execsql_test_on_specific_db {:memory:} select-intersect-union-with-limit { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'), ('z','z'); INSERT INTO u VALUES('d','d'),('e','e'), ('z','z'); INSERT INTO v VALUES('a','a'),('b','b'); select * from t INTERSECT select * from u UNION select * from v limit 3; } {a|a b|b z|z} do_execsql_test_on_specific_db {:memory:} select-except-1 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); select * from t EXCEPT select * from u; } {y|y} do_execsql_test_on_specific_db {:memory:} select-except-2 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('y','y'); select * from t EXCEPT select * from u; } {} do_execsql_test_on_specific_db {:memory:} select-except-3 { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('a','y'); INSERT INTO v VALUES('a','x'),('b','y'); select * from t EXCEPT select * from u EXCEPT select * from v; } {y|y} do_execsql_test_on_specific_db {:memory:} select-except-limit { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); INSERT INTO t VALUES('a', 'a'),('x','x'),('y','y'),('z','z'); INSERT INTO u VALUES('x','x'),('z','y'); select * from t EXCEPT select * from u limit 2; } {a|a y|y} do_execsql_test_on_specific_db {:memory:} select-except-union-all { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t EXCEPT select * from u UNION ALL select * from v; } {y|y x|x y|y} do_execsql_test_on_specific_db {:memory:} select-union-all-except { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('y','y'); select * from t UNION ALL select * from u EXCEPT select * from v; } {z|y} do_execsql_test_on_specific_db {:memory:} select-except-union { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t EXCEPT select * from u UNION select * from v; } {x|x y|y z|z} do_execsql_test_on_specific_db {:memory:} select-union-except { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t UNION select * from u EXCEPT select * from v; } {y|y z|y} do_execsql_test_on_specific_db {:memory:} select-except-intersect { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('y','y'),('z','z'); select * from t EXCEPT select * from u INTERSECT select * from v; } {y|y} do_execsql_test_on_specific_db {:memory:} select-intersect-except { CREATE TABLE t (x TEXT, y TEXT); CREATE TABLE u (x TEXT, y TEXT); CREATE TABLE v (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); INSERT INTO u VALUES('x','x'),('z','y'); INSERT INTO v VALUES('x','x'),('z','z'); select * from t INTERSECT select * from u EXCEPT select * from v; } {} do_execsql_test_on_specific_db {:memory:} select-values-union { CREATE TABLE t (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); values('x', 'x') UNION select * from t; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-values-union-2 { CREATE TABLE t (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); values('x', 'x'), ('y', 'y') UNION select * from t; } {x|x y|y} do_execsql_test_on_specific_db {:memory:} select-values-except { CREATE TABLE t (x TEXT, y TEXT); INSERT INTO t VALUES('x','x'),('y','y'); select * from t EXCEPT values('x','x'),('z','y'); } {y|y} do_execsql_test_on_specific_db {:memory:} select-values-union-all-limit { CREATE TABLE t (x TEXT); INSERT INTO t VALUES('x'), ('y'), ('z'); values('x') UNION ALL select * from t limit 3; } {x x y} do_execsql_test_on_specific_db {:memory:} select-values-union-all-limit-1 { CREATE TABLE t (x TEXT); INSERT INTO t VALUES('x'), ('y'), ('z'); values('a'), ('b') UNION ALL select * from t limit 3; } {a b x} do_execsql_test_on_specific_db {:memory:} select-values-union-all-offset { CREATE TABLE t (x TEXT); INSERT INTO t VALUES('x'), ('y'), ('z'); values('a'), ('b') UNION ALL select * from t limit 3 offset 1; } {b x y} do_execsql_test_on_specific_db {:memory:} select-values-union-all-offset-1 { CREATE TABLE t (x TEXT); INSERT INTO t VALUES('i'), ('j'), ('x'), ('y'), ('z'); values('a') UNION ALL select * from t limit 3 offset 1; } {i j x} do_execsql_test_on_specific_db {:memory:} select-no-match-in-leaf-page { CREATE TABLE t (a INTEGER PRIMARY KEY, b); insert into t values (1, randomblob(1024)); insert into t values (2, randomblob(1024)); insert into t values (3, randomblob(1024)); insert into t values (4, randomblob(1024)); insert into t values (5, randomblob(1024)); insert into t values (6, randomblob(1024)); insert into t values (7, randomblob(1024)); insert into t values (8, randomblob(1024)); insert into t values (9, randomblob(1024)); insert into t values (10, randomblob(1024)); insert into t values (11, randomblob(1024)); insert into t values (12, randomblob(1024)); insert into t values (13, randomblob(1024)); insert into t values (14, randomblob(1024)); insert into t values (15, randomblob(1024)); insert into t values (16, randomblob(1024)); delete from t where a in (3, 6, 9, 12); select count(*) from t where a >= 2; select count(*) from t where a >= 3; select count(*) from t where a >= 4; select count(*) from t where a > 1; select count(*) from t where a > 2; select count(*) from t where a > 3; select count(*) from t where a <= 3 ORDER BY a DESC; select count(*) from t where a <= 4 ORDER BY a DESC; select count(*) from t where a <= 5 ORDER BY a DESC; select count(*) from t where a < 2 ORDER BY a DESC; select count(*) from t where a < 3 ORDER BY a DESC; select count(*) from t where a < 4 ORDER BY a DESC; } {11 10 10 11 10 10 2 3 4 1 2 2} do_execsql_test_on_specific_db {:memory:} select-range-search-count-asc-index { CREATE TABLE t (a, b); CREATE INDEX t_idx ON t(a, b); insert into t values (1, 1); insert into t values (1, 2); insert into t values (1, 3); insert into t values (1, 4); insert into t values (1, 5); insert into t values (1, 6); insert into t values (2, 1); insert into t values (2, 2); insert into t values (2, 3); insert into t values (2, 4); insert into t values (2, 5); insert into t values (2, 6); select count(*) from t where a = 1 AND b >= 2 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b > 2 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b <= 4 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b < 4 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b >= 2 AND b <= 4 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b > 2 AND b <= 4 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b >= 2 AND b < 4 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b > 2 AND b < 4 ORDER BY a ASC, b ASC; select count(*) from t where a = 1 AND b >= 2 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b > 2 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b <= 4 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b < 4 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b >= 2 AND b <= 4 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b > 2 AND b <= 4 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b >= 2 AND b < 4 ORDER BY a DESC, b DESC; select count(*) from t where a = 1 AND b > 2 AND b < 4 ORDER BY a DESC, b DESC; } {5 4 4 3 3 2 2 1 5 4 4 3 3 2 2 1} do_execsql_test_on_specific_db {:memory:} select-range-search-count-desc-index { CREATE TABLE t (a, b); CREATE INDEX t_idx ON t(a, b DESC); insert into t values (1, 1); insert into t values (1, 2); insert into t values (1, 3); insert into t values (1, 4); insert into t values (1, 5); insert into t values (1, 6); insert into t values (2, 1); insert into t values (2, 2); insert into t values (2, 3); insert into t values (2, 4); insert into t values (2, 5); insert into t values (2, 6); select count(*) from t where a = 1 AND b >= 2 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b > 2 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b <= 4 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b < 4 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b >= 2 AND b <= 4 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b > 2 AND b <= 4 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b >= 2 AND b < 4 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b > 2 AND b < 4 ORDER BY a ASC, b DESC; select count(*) from t where a = 1 AND b >= 2 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b > 2 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b <= 4 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b < 4 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b >= 2 AND b <= 4 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b > 2 AND b <= 4 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b >= 2 AND b < 4 ORDER BY a DESC, b ASC; select count(*) from t where a = 1 AND b > 2 AND b < 4 ORDER BY a DESC, b ASC; } {5 4 4 3 3 2 2 1 5 4 4 3 3 2 2 1} do_execsql_test_on_specific_db {:memory:} select-range-search-scan-asc-index { CREATE TABLE t (a, b); CREATE INDEX t_idx ON t(a, b); insert into t values (1, 1); insert into t values (1, 2); insert into t values (1, 3); insert into t values (1, 4); insert into t values (1, 5); insert into t values (1, 6); insert into t values (2, 1); insert into t values (2, 2); insert into t values (2, 3); insert into t values (2, 4); insert into t values (2, 5); insert into t values (2, 6); select * from t where a = 1 AND b > 1 AND b < 6 ORDER BY a ASC, b ASC; select * from t where a = 2 AND b > 1 AND b < 6 ORDER BY a DESC, b DESC; select * from t where a = 1 AND b > 1 AND b < 6 ORDER BY a DESC, b ASC; select * from t where a = 2 AND b > 1 AND b < 6 ORDER BY a ASC, b DESC; } {1|2 1|3 1|4 1|5 2|5 2|4 2|3 2|2 1|2 1|3 1|4 1|5 2|5 2|4 2|3 2|2} do_execsql_test_on_specific_db {:memory:} select-range-search-scan-desc-index { CREATE TABLE t (a, b); CREATE INDEX t_idx ON t(a, b DESC); insert into t values (1, 1); insert into t values (1, 2); insert into t values (1, 3); insert into t values (1, 4); insert into t values (1, 5); insert into t values (1, 6); insert into t values (2, 1); insert into t values (2, 2); insert into t values (2, 3); insert into t values (2, 4); insert into t values (2, 5); insert into t values (2, 6); select * from t where a = 1 AND b > 1 AND b < 6 ORDER BY a ASC, b ASC; select * from t where a = 2 AND b > 1 AND b < 6 ORDER BY a DESC, b DESC; select * from t where a = 1 AND b > 1 AND b < 6 ORDER BY a DESC, b ASC; select * from t where a = 2 AND b > 1 AND b < 6 ORDER BY a ASC, b DESC; } {1|2 1|3 1|4 1|5 2|5 2|4 2|3 2|2 1|2 1|3 1|4 1|5 2|5 2|4 2|3 2|2} # Regression tests for double-quoted strings in SELECT statements do_execsql_test_skip_lines_on_specific_db 1 {:memory:} select-double-quotes-values { .dbconfig dqs_dml on SELECT * FROM (VALUES ("select", "test"), ("double", "quotes")); } {select|test double|quotes} do_execsql_test_skip_lines_on_specific_db 1 {:memory:} select-double-quotes-no-column { .dbconfig dqs_dml on SELECT "first" } {first} do_execsql_test_skip_lines_on_specific_db 1 {:memory:} select-double-quotes-literal { .dbconfig dqs_dml on SELECT "literal_string" AS col; } {literal_string} do_execsql_test_on_specific_db {:memory:} select-in-simple { SELECT 1 IN (1, 2, 3); SELECT 4 IN (1, 2, 3); } {1 0} do_execsql_test_on_specific_db {:memory:} select-in-with-nulls { SELECT 4 IN (1, 4, null); SELECT 4 NOT IN (1, 4, null); } {1 0} # All should be null do_execsql_test_on_specific_db {:memory:} select-in-with-nulls-2 { SELECT 1 IN (2, 3, null); SELECT 1 NOT IN (2, 3, null); SELECT null in (null); } {\n\n} do_execsql_test_on_specific_db {:memory:} select-in-complex { CREATE TABLE test_table (id INTEGER, category TEXT, value INTEGER); INSERT INTO test_table VALUES (1, 'A', 10), (2, 'B', 20), (3, 'A', 30), (4, 'C', 40); SELECT * FROM test_table WHERE category IN ('A', 'B') AND value IN (10, 30, 40); } {1|A|10 3|A|30} foreach {testname limit ans} { limit-const-1 1 {1} limit-text-2 '2' {1 2} limit-bool-true true {1} limit-expr-add 1+2+3 {1 2 3 4 5 6} limit-expr-sub 5-2-3 {} limit-expr-paren (1+1)*2 {1 2 3 4} limit-bool-add true+2 {1 2 3} limit-text-math '2'*2+1 {1 2 3 4 5} limit-bool-false-add false+4 {1 2 3 4} limit-mixed-math (1+'1')*(1+1)-(5/5) {1 2 3} limit-text-bool ('false'+2) {1 2} limit-coalesce COALESCE(NULL,0+1) {1} } { do_execsql_test limit-complex-exprs-$testname \ "SELECT id FROM users ORDER BY id LIMIT $limit" $ans } do_execsql_test_on_specific_db {:memory:} limit-expr-can-be-cast-losslessly-1 { SELECT 1 LIMIT 1.1 + 2.9; } {1} do_execsql_test_on_specific_db {:memory:} limit-expr-can-be-cast-losslessly-2 { CREATE TABLE T(a); INSERT INTO T VALUES (1),(1),(1),(1); SELECT * FROM T LIMIT 1.6/2 + 3.6/3 + 4*0.25; } {1 1 1} # Numeric strings are cast to float. The final evaluation of the expression returns an int losslessly do_execsql_test_on_specific_db {:memory:} limit-expr-can-be-cast-losslessly-3 { CREATE TABLE T(a); INSERT INTO T VALUES (1),(1),(1),(1); SELECT * FROM T LIMIT '0.8' + '1.2' + 4*0.25; } {1 1 1} # Invalid strings are cast to 0. So expression is valid do_execsql_test_on_specific_db {:memory:} limit-expr-int-and-string { SELECT 1 LIMIT 3/3 + 'test' + 4*'test are best'; } {1} do_execsql_test_in_memory_error_content limit-expr-cannot-be-cast-losslessly-1 { SELECT 1 LIMIT 1.1; } {"datatype mismatch"} do_execsql_test_in_memory_error_content limit-expr-cannot-be-cast-losslessly-2 { SELECT 1 LIMIT 1.1 + 2.2 + 1.9/8; } {"datatype mismatch"} # Return error as float in the expression cannot be cast losslessly do_execsql_test_in_memory_error_content limit-expr-cannot-be-cast-losslessly-3 { SELECT 1 LIMIT 1.1 +'a'; } {"datatype mismatch"} do_execsql_test_in_memory_error_content limit-expr-invalid-data-type-1 { SELECT 1 LIMIT 'a'; } {"datatype mismatch"} do_execsql_test_in_memory_error_content limit-expr-invalid-data-type-2 { SELECT 1 LIMIT NULL; } {"datatype mismatch"} # The expression below evaluates to NULL as string is cast to 0 do_execsql_test_in_memory_error_content limit-expr-invalid-data-type-3 { SELECT 1 LIMIT 1/'iwillbezero ;-; ' ; } {"datatype mismatch"} # Expression is evaluated as NULL do_execsql_test_in_memory_error_content limit-expr-invalid-data-type-4 { SELECT 1 LIMIT 4+NULL; } {"datatype mismatch"} do_execsql_test_on_specific_db {:memory:} rowid-references { CREATE TABLE test_table (id INTEGER); INSERT INTO test_table VALUES (5),(5); SELECT rowid, "rowid", `rowid`, [rowid], _rowid_, "_rowid_", `_rowid_`, [_rowid_], oid, "oid", `oid`, [oid] FROM test_table WHERE rowid = 2 AND "rowid" = 2 AND `rowid` = 2 AND [rowid] = 2 AND _rowid_ = 2 AND "_rowid_" = 2 AND `_rowid_` = 2 AND [_rowid_] = 2 AND oid = 2 AND "oid" = 2 AND `oid` = 2 AND [oid] = 2; } {2|2|2|2|2|2|2|2|2|2|2|2} do_execsql_test_on_specific_db {:memory:} null-in-search { CREATE TABLE t_x_asc (id INTEGER PRIMARY KEY, x); CREATE INDEX t_x_asc_idx ON t_x_asc(x ASC); CREATE TABLE t_x_desc (id INTEGER PRIMARY KEY, x); CREATE INDEX t_x_desc_idx ON t_x_desc(x DESC); INSERT INTO t_x_asc VALUES (1, NULL), (2, 2), (10, 10); INSERT INTO t_x_desc VALUES (1, NULL), (2, 2), (10, 10); SELECT * FROM t_x_asc WHERE x > 5 ORDER BY x ASC; SELECT * FROM t_x_asc WHERE x > 5 ORDER BY x DESC; SELECT * FROM t_x_asc WHERE x < 5 ORDER BY x ASC; SELECT * FROM t_x_asc WHERE x < 5 ORDER BY x DESC; SELECT * FROM t_x_desc WHERE x > 5 ORDER BY x ASC; SELECT * FROM t_x_desc WHERE x > 5 ORDER BY x DESC; SELECT * FROM t_x_desc WHERE x < 5 ORDER BY x ASC; SELECT * FROM t_x_desc WHERE x < 5 ORDER BY x DESC; } {10|10 10|10 2|2 2|2 10|10 10|10 2|2 2|2} do_execsql_test_in_memory_any_error limit-column-reference-error { CREATE TABLE t(a); SELECT * FROM t LIMIT (t.a); } do_execsql_test select-binary-collation { SELECT 'a' = 'A'; SELECT 'a' = 'a'; } {0 1}