diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/colname.test | 55 | ||||
-rw-r--r-- | test/like.test | 50 | ||||
-rw-r--r-- | test/ossfuzz.c | 25 | ||||
-rw-r--r-- | test/schema6.test | 163 | ||||
-rw-r--r-- | test/without_rowid1.test | 14 |
5 files changed, 305 insertions, 2 deletions
diff --git a/test/colname.test b/test/colname.test index e16304d4a..1497fc275 100644 --- a/test/colname.test +++ b/test/colname.test @@ -13,7 +13,6 @@ # The focus of this file is testing how SQLite generates the names # of columns in a result set. # -# $Id: colname.test,v 1.7 2009/06/02 15:47:38 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -326,4 +325,58 @@ do_test colname-8.1 { } } {123} +# 2017-07-29: Interaction between column naming and query flattening. +# For years now, the query flattener has inserted AS clauses on the +# outer query that were the original SQL text of the column. This caused +# column-name shifts when the query flattener was enhanced, breaking +# legacy applications. See https://sqlite.org/src/info/41c27bc0ff1d3135 +# for details. +# +# To fix this, the column naming logic was moved ahead of the query +# flattener so that column names are assigned before the query flattener +# runs. +# +db close +sqlite3 db :memory: +do_test colname-9.100 { + db eval { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2); + CREATE VIEW v1(x,y) AS SELECT a,b FROM t1; + } + execsql2 {SELECT v1.x, (Y) FROM v1} + # Prior to the fix, this would return: "v1.x 1 (Y) 2" +} {x 1 y 2} +do_test colname-9.110 { + execsql2 {SELECT * FROM v1} +} {x 1 y 2} +do_test colname-9.120 { + db eval { + CREATE VIEW v2(x,y) AS SELECT a,b FROM t1 LIMIT 10; + } + execsql2 {SELECT * FROM v2 WHERE 1} +} {x 1 y 2} +do_test colname-9.130 { + execsql2 {SELECT v2.x, [v2].[y] FROM v2 WHERE 1} +} {x 1 y 2} +do_test colname-9.140 { + execsql2 {SELECT +x, +y FROM v2 WHERE 1} +} {+x 1 +y 2} + +do_test colname-9.200 { + db eval { + CREATE TABLE t2(c,d); + INSERT INTO t2 VALUES(3,4); + CREATE VIEW v3 AS SELECT c AS a, d AS b FROM t2; + } + execsql2 {SELECT t1.a, v3.a AS n FROM t1 LEFT JOIN v3} +} {a 1 n 3} +do_test colname-9.211 { + execsql2 {SELECT t1.a AS n, v3.a FROM t1 JOIN v3} +} {n 1 a 3} +do_test colname-9.210 { + execsql2 {SELECT t1.a, v3.a AS n FROM t1 JOIN v3} +} {a 1 n 3} + + finish_test diff --git a/test/like.test b/test/like.test index bae770b07..1702dde71 100644 --- a/test/like.test +++ b/test/like.test @@ -207,7 +207,7 @@ do_test like-3.3.100 { SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1; } } {abc abcd nosort {} i1} -do_test like-3.3.101 { +do_test like-3.3.100.cnt { set sqlite_like_count } 0 @@ -1048,4 +1048,52 @@ ifcapable !icu { } {1} } +# As of 2017-07-27 (3.21.0) the LIKE optimization works with ESCAPE as +# long as the ESCAPE is a single-byte literal. +# +db close +sqlite3 db :memory: +do_execsql_test like-15.100 { + CREATE TABLE t15(x TEXT COLLATE nocase, y, PRIMARY KEY(x)); + INSERT INTO t15(x,y) VALUES + ('abcde',1), ('ab%de',2), ('a_cde',3), + ('uvwxy',11),('uvwx%',12),('uvwx_',13), + ('_bcde',21),('%bcde',22), + ('abcd_',31),('abcd%',32), + ('ab%xy',41); + SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '/'; +} {2} +do_execsql_test like-15.101 { + EXPLAIN QUERY PLAN + SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '/'; +} {/SEARCH/} +do_execsql_test like-15.102 { + EXPLAIN QUERY PLAN + SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '//'; +} {/SCAN/} +do_execsql_test like-15.103 { + EXPLAIN QUERY PLAN + SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE ''; +} {/SCAN/} +do_execsql_test like-15.110 { + SELECT y FROM t15 WHERE x LIKE 'abcdx%%' ESCAPE 'x'; +} {32} +do_execsql_test like-15.111 { + SELECT y FROM t15 WHERE x LIKE 'abx%%' ESCAPE 'x' ORDER BY +y +} {2 41} +do_execsql_test like-15.112 { + EXPLAIN QUERY PLAN + SELECT y FROM t15 WHERE x LIKE 'abx%%' ESCAPE 'x' ORDER BY +y +} {/SEARCH/} +do_execsql_test like-15.120 { + SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/'; +} {22} +do_execsql_test like-15.121 { + EXPLAIN QUERY PLAN + SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/'; +} {/SEARCH/} + + + + finish_test diff --git a/test/ossfuzz.c b/test/ossfuzz.c index 51983548b..7b28cf6a7 100644 --- a/test/ossfuzz.c +++ b/test/ossfuzz.c @@ -71,6 +71,28 @@ static int progress_handler(void *pClientData) { #endif /* +** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and +** "PRAGMA parser_trace" since they can dramatically increase the +** amount of output without actually testing anything useful. +*/ +static int block_debug_pragmas( + void *Notused, + int eCode, + const char *zArg1, + const char *zArg2, + const char *zArg3, + const char *zArg4 +){ + if( eCode==SQLITE_PRAGMA + && (sqlite3_strnicmp("vdbe_", zArg1, 5)==0 + || sqlite3_stricmp("parser_trace", zArg1)==0) + ){ + return SQLITE_DENY; + } + return SQLITE_OK; +} + +/* ** Callback for sqlite3_exec(). */ static int exec_handler(void *pCnt, int argc, char **argv, char **namev){ @@ -128,6 +150,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc); uSelector >>= 1; + /* Do not allow debugging pragma statements that might cause excess output */ + sqlite3_set_authorizer(cx.db, block_debug_pragmas, 0); + /* Remaining bits of the selector determine a limit on the number of ** output rows */ execCnt = uSelector + 1; diff --git a/test/schema6.test b/test/schema6.test new file mode 100644 index 000000000..7de04d51c --- /dev/null +++ b/test/schema6.test @@ -0,0 +1,163 @@ +# 2017-07-30 +# +# 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. +# +#*********************************************************************** +# +# This file implements tests to show that certain CREATE TABLE statements +# generate identical database files. For example, changes in identifier +# names, white-space, and formatting of the CREATE TABLE statement should +# produce identical table content. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix schema6 + +# Command: check_same_database_content TESTNAME SQL1 SQL2 SQL3 ... +# +# This command creates fresh databases using SQL1 and subsequent arguments +# and checks to make sure the content of all database files is byte-for-byte +# identical. Page 1 of the database files is allowed to be different, since +# page 1 contains the sqlite_master table which is expected to vary. +# +proc check_same_database_content {basename args} { + set i 0 + set hash {} + foreach sql $args { + catch {db close} + forcedelete test.db + sqlite3 db test.db + db eval $sql + set pgsz [db one {PRAGMA page_size}] + db close + set sz [file size test.db] + set thishash [md5file test.db $pgsz [expr {$sz-$pgsz}]] + if {$i==0} { + set hash $thishash + } else { + do_test $basename-$i "set x $thishash" $hash + } + incr i + } +} + +# Command: check_different_database_content TESTNAME SQL1 SQL2 SQL3 ... +# +# This command creates fresh databases using SQL1 and subsequent arguments +# and checks to make sure the content of all database files is different +# in ways other than on page 1. +# +proc check_different_database_content {basename args} { + set i 0 + set hashes {} + foreach sql $args { + forcedelete test.db + sqlite3 db test.db + db eval $sql + set pgsz [db one {PRAGMA page_size}] + db close + set sz [file size test.db] + set thishash [md5file test.db $pgsz [expr {$sz-$pgsz}]] + set j [lsearch $hashes $thishash] + if {$j>=0} { + do_test $basename-$i "set x {$i is the same as $j}" "All are different" + } else { + do_test $basename-$i "set x {All are different}" "All are different" + } + lappend hashes $thishash + incr i + } +} + +check_same_database_content 100 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(xyz INTEGER, abc, PRIMARY KEY(xyz), UNIQUE(abc)); + INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(xyz INTEGER, abc, UNIQUE(abc), PRIMARY KEY(xyz)); + INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY ASC, b UNIQUE); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + CREATE UNIQUE INDEX t1b ON t1(b); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); + CREATE UNIQUE INDEX t1b ON t1(b); +} + +check_same_database_content 110 { + CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE, UNIQUE(a)); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b); + CREATE UNIQUE INDEX t1b ON t1(b); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); + CREATE UNIQUE INDEX t1b ON t1(b); +} + +check_same_database_content 120 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE) WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(xyz INTEGER, abc, PRIMARY KEY(xyz), UNIQUE(abc))WITHOUT ROWID; + INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(xyz INTEGER, abc, UNIQUE(abc), PRIMARY KEY(xyz))WITHOUT ROWID; + INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY ASC, b UNIQUE) WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE) WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE) WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE, UNIQUE(a)) + WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID; + CREATE UNIQUE INDEX t1b ON t1(b); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); + CREATE UNIQUE INDEX t1b ON t1(b); +} + +check_different_database_content 130 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE); + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE) WITHOUT ROWID; + INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...'); +} + + +finish_test diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 0c77773ab..c7899cfb3 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -328,5 +328,19 @@ do_catchsql_test 7.3 { ) WITHOUT ROWID; } {1 {no such column: rowid}} +# 2017-07-30: OSSFuzz discovered that an extra entry was being +# added in the sqlite_master table for an "INTEGER PRIMARY KEY UNIQUE" +# WITHOUT ROWID table. Make sure this has now been fixed. +# +db close +sqlite3 db :memory: +do_execsql_test 8.1 { + CREATE TABLE t1(x INTEGER PRIMARY KEY UNIQUE, b) WITHOUT ROWID; + CREATE INDEX t1x ON t1(x); + INSERT INTO t1(x,b) VALUES('funny','buffalo'); + SELECT type, name, '|' FROM sqlite_master; +} {table t1 | index t1x |} + + finish_test |