1
0
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:
drh
2024-04-05 15:04:01 +00:00
18 changed files with 421 additions and 83 deletions

View File

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

View File

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

View File

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

View File

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

View File

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