mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Merge all recent trunk enhancements into the reuse-schema branch.
FossilOrigin-Name: e556f3d3819134022f72e72471976616700c4fe00fc924bfbe713a6132440fdf
This commit is contained in:
@@ -763,4 +763,27 @@ do_execsql_test 30.2 {
|
||||
)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 31.0 {
|
||||
CREATE TABLE t1(ii INTEGER PRIMARY KEY, tt INTEGER, rr REAL);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000
|
||||
)
|
||||
INSERT INTO t1 SELECT NULL, i, 5.0 FROM s;
|
||||
}
|
||||
|
||||
do_test 31.1 {
|
||||
set pg [db one {PRAGMA page_count}]
|
||||
execsql {
|
||||
ALTER TABLE t1 DROP COLUMN tt;
|
||||
}
|
||||
set pg2 [db one {PRAGMA page_count}]
|
||||
expr $pg==$pg2
|
||||
} {1}
|
||||
|
||||
do_execsql_test 31.2 {
|
||||
SELECT rr FROM t1 LIMIT 1
|
||||
} {5.0}
|
||||
|
||||
finish_test
|
||||
|
@@ -135,10 +135,10 @@ reset_db
|
||||
do_catchsql_test default-5.1 {
|
||||
CREATE TABLE t1 (a,b DEFAULT(random() NOTNULL IN (RAISE(IGNORE),2,3)));
|
||||
INSERT INTO t1(a) VALUES(1);
|
||||
} {1 {RAISE() may only be used within a trigger-program}}
|
||||
} {1 {default value of column [b] is not constant}}
|
||||
do_catchsql_test default-5.2 {
|
||||
CREATE TABLE Table0 (Col0 DEFAULT (RAISE(IGNORE) ) ) ;
|
||||
INSERT INTO Table0 DEFAULT VALUES ;
|
||||
} {1 {RAISE() may only be used within a trigger-program}}
|
||||
} {1 {default value of column [Col0] is not constant}}
|
||||
|
||||
finish_test
|
||||
|
@@ -149,7 +149,7 @@ ifcapable icu {
|
||||
# 2020-03-19
|
||||
# The ESCAPE clause on LIKE takes precedence over wildcards
|
||||
#
|
||||
do_execsql_test idu-6.0 {
|
||||
do_execsql_test icu-6.0 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(id INTEGER PRIMARY KEY, x TEXT);
|
||||
INSERT INTO t1 VALUES
|
||||
@@ -164,4 +164,20 @@ do_execsql_test icu-6.1 {
|
||||
SELECT id FROM t1 WHERE x LIKE 'abc__' ESCAPE '_';
|
||||
} {2}
|
||||
|
||||
# 2024-04-02
|
||||
# Optional 3rd argument to icu_load_collation() that specifies
|
||||
# the "strength" of comparison.
|
||||
#
|
||||
reset_db
|
||||
do_catchsql_test icu-7.1 {
|
||||
SELECT icu_load_collation('en_US','error','xyzzy');
|
||||
} {1 {unknown collation strength "xyzzy" - should be one of: PRIMARY SECONDARY TERTIARY DEFAULT QUARTERNARY IDENTICAL}}
|
||||
do_execsql_test icu-7.2 {
|
||||
SELECT icu_load_collation('en_US','prim','PRIMARY'),
|
||||
icu_load_collation('en_US','dflt','DEFAULT');
|
||||
} {{} {}}
|
||||
do_execsql_test icu-7.3 {
|
||||
SELECT char(0x100)=='a', char(0x100)=='a' COLLATE dflt, char(0x100)=='a' COLLATE prim;
|
||||
} {0 0 1}
|
||||
|
||||
finish_test
|
||||
|
@@ -309,4 +309,36 @@ do_execsql_test 12.3 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# 2024-04-05 dbsqlfuzz b9e65e2f110df998f1306571fae7af6c01e4d92b
|
||||
reset_db
|
||||
do_execsql_test 13.1 {
|
||||
CREATE TABLE t1(a INT AS (b), b INT);
|
||||
INSERT INTO t1(b) VALUES(123);
|
||||
CREATE TABLE t2(a INT, c INT);
|
||||
SELECT a FROM t2 NATURAL RIGHT JOIN t1;
|
||||
} {123}
|
||||
do_execsql_test 13.2 {
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
SELECT a FROM t2 NATURAL RIGHT JOIN t1;
|
||||
} {123}
|
||||
# Further tests of the same logic (indexes on expressions
|
||||
# used by RIGHT JOIN) from check-in ffe23af73fcb324d and
|
||||
# forum post https://sqlite.org/forum/forumpost/9b491e1debf0b67a.
|
||||
db null NULL
|
||||
do_execsql_test 13.3 {
|
||||
CREATE TABLE t3(a INT, b INT);
|
||||
CREATE UNIQUE INDEX t3x ON t3(a, a+b);
|
||||
INSERT INTO t3(a,b) VALUES(1,2),(4,8),(16,32),(4,80),(1,-300);
|
||||
CREATE TABLE t4(x INT, y INT);
|
||||
INSERT INTO t4(x,y) SELECT a, b FROM t3;
|
||||
INSERT INTO t4(x,y) VALUES(99,99);
|
||||
SELECT a1.a, sum( a1.a+a1.b ) FROM t3 AS a1 RIGHT JOIN t4 ON a=x
|
||||
GROUP BY a1.a ORDER BY 1;
|
||||
} {NULL NULL 1 -592 4 192 16 48}
|
||||
do_execsql_test 13.4 {
|
||||
SELECT sum( a1.a+a1.b ) FROM t3 AS a1 RIGHT JOIN t3 ON true
|
||||
GROUP BY a1.a ORDER BY 1;
|
||||
} {-1480 240 480}
|
||||
|
||||
finish_test
|
||||
|
@@ -31,10 +31,7 @@ proc vtab_command {method args} {
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
}
|
||||
|
||||
breakpoint
|
||||
foreach {tn cts} {
|
||||
1 {SELECT 123}
|
||||
2 {SELECT 123, 456}
|
||||
@@ -44,6 +41,8 @@ foreach {tn cts} {
|
||||
6 {DROP TABLE nosuchtable}
|
||||
7 {DROP TABLE x1}
|
||||
8 {DROP TABLE t1}
|
||||
9 {CREATE TABLE xyz AS SELECT * FROM sqlite_schema}
|
||||
10 {CREATE TABLE xyz AS SELECT 1 AS 'col'}
|
||||
} {
|
||||
set ::create_table_sql $cts
|
||||
do_catchsql_test 1.$tn {
|
||||
@@ -51,5 +50,19 @@ foreach {tn cts} {
|
||||
} {1 {vtable constructor failed: x1}}
|
||||
}
|
||||
|
||||
foreach {tn cts} {
|
||||
1 {CREATE TABLE IF NOT EXISTS t1(a, b)}
|
||||
2 {CREATE TABLE ""(a, b PRIMARY KEY) WITHOUT ROWID}
|
||||
} {
|
||||
set ::create_table_sql $cts
|
||||
execsql { DROP TABLE IF EXISTS x1 }
|
||||
do_execsql_test 2.$tn.1 {
|
||||
CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
|
||||
}
|
||||
do_execsql_test 2.$tn.2 {
|
||||
SELECT a, b FROM x1
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
103
test/whereN.test
Normal file
103
test/whereN.test
Normal file
@@ -0,0 +1,103 @@
|
||||
# 2024-04-02
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Tests for the whereInterstageHeuristic() routine in the query planner.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix whereN
|
||||
|
||||
# The following is a simplified and "sanitized" version of the original
|
||||
# real-world query that brought the problem to light.
|
||||
#
|
||||
# The issue is a slow query. The answer is correct, but it was taking too
|
||||
# much time, because it was doing a full table scan rather than an indexed
|
||||
# lookup.
|
||||
#
|
||||
# The problem was that the query planner was overestimating the number of
|
||||
# output rows. The estimated number of output rows is accurate if the
|
||||
# DSNAME parameter is "ds-one". In that case, a large fraction of the rows
|
||||
# in "violation" end up being output. The query planner correctly deduces
|
||||
# that it is faster to do a full table scan of the large "violation" table
|
||||
# to avoid the after-query sort that implements the ORDER BY clause. However,
|
||||
# if the DSNAME is "ds-two", then only a few rows (about 6) are generated,
|
||||
# and it is much much faster to do an indexed lookup of "violation" followed
|
||||
# by a sort operation to implement ORDER BY
|
||||
#
|
||||
# The problem, of course, is that the query planner has no way of knowing
|
||||
# in advance how many rows will be generated. The query planner tries to
|
||||
# estimate a worst case, which is a large number of output rows, and it picks
|
||||
# the best plan for that case. However, the plan choosen is very inefficient
|
||||
# when the number of output rows is small.
|
||||
#
|
||||
# The whereInterstageHeuristic() routine in the query planner attempts to
|
||||
# correct this by adjusting the query plan such that it avoids the very bad
|
||||
# query plan for a small number of rows, at the expense of a slightly less
|
||||
# efficient plan for a large number of rows. The large number of rows case
|
||||
# is perhaps 5% slower with the revised plan, but the small number of
|
||||
# rows case is around 100 times faster. That seems like a good tradeoff.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE datasource(dsid INT, name TEXT);
|
||||
INSERT INTO datasource VALUES(1,'ds-one'),(2,'ds-two'),(3,'ds-three');
|
||||
CREATE INDEX ds1 ON datasource(name, dsid);
|
||||
|
||||
CREATE TABLE rule(rid INT, team_id INT, dsid INT);
|
||||
WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<9)
|
||||
INSERT INTO rule(rid,team_id,dsid) SELECT n, 1, 1 FROM c;
|
||||
WITH RECURSIVE c(n) AS (VALUES(10) UNION ALL SELECT n+1 FROM c WHERE n<24)
|
||||
INSERT INTO rule(rid,team_id,dsid) SELECT n, 2, 2 FROM c;
|
||||
CREATE INDEX rule2 ON rule(dsid, rid);
|
||||
|
||||
CREATE TABLE violation(vid INT, rid INT, vx BLOB);
|
||||
/*** Uncomment to insert actual data
|
||||
WITH src(rid, cnt) AS (VALUES(1,3586),(2,1343),(3,6505),(5,76230),
|
||||
(6,740),(7,287794),(8,457),(12,1),
|
||||
(14,1),(16,1),(17,1),(18,1),(19,1))
|
||||
INSERT INTO violation(vid, rid, vx)
|
||||
SELECT rid*1000000+value, rid, randomblob(15)
|
||||
FROM src, generate_series(1,cnt);
|
||||
***/
|
||||
CREATE INDEX v1 ON violation(rid, vid);
|
||||
CREATE INDEX v2 ON violation(vid);
|
||||
ANALYZE;
|
||||
DELETE FROM sqlite_stat1;
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
INSERT INTO sqlite_stat1 VALUES
|
||||
('violation','v2','376661 1'),
|
||||
('violation','v1','376661 28974 1'),
|
||||
('rule','rule2','24 12 1'),
|
||||
('datasource','ds1','3 1 1');
|
||||
ANALYZE sqlite_schema;
|
||||
}
|
||||
set DSNAME ds-two ;# Only a few rows. Change to "ds-one" for many rows.
|
||||
do_eqp_test 1.1 {
|
||||
SELECT count(*), length(group_concat(vx)) FROM (
|
||||
SELECT V.*
|
||||
FROM datasource DS, rule R, violation V
|
||||
WHERE V.rid=R.rid
|
||||
AND R.dsid=DS.dsid
|
||||
AND DS.name=$DSNAME
|
||||
ORDER BY V.vid desc
|
||||
);
|
||||
} {
|
||||
QUERY PLAN
|
||||
|--CO-ROUTINE (subquery-xxxxxx)
|
||||
| |--SEARCH DS USING COVERING INDEX ds1 (name=?)
|
||||
| |--SEARCH R USING COVERING INDEX rule2 (dsid=?)
|
||||
| |--SEARCH V USING INDEX v1 (rid=?)
|
||||
| `--USE TEMP B-TREE FOR ORDER BY
|
||||
`--SCAN (subquery-xxxxxx)
|
||||
}
|
||||
# ^^^^---- We want to see three SEARCH terms. No SCAN terms.
|
||||
# The ORDER BY is implemented by a separate sorter pass.
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user