add sqlite 3.3.8 to in tree libs

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3735 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris
2006-12-19 20:11:50 +00:00
parent 3b35430557
commit 165f180162
387 changed files with 234653 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
# 2006 January 20
#
# 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 regression tests for SQLite library.
#
# This file implements tests for calling sqlite3_result_error()
# from within an aggregate function implementation.
#
# $Id: aggerror.test,v 1.3 2006/05/03 23:34:06 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Add the x_count aggregate function to the database handle.
# x_count will error out if its input is 40 or 41 or if its
# final results is 42. Make sure that such errors are handled
# appropriately.
#
do_test aggerror-1.1 {
set DB [sqlite3_connection_pointer db]
sqlite3_create_aggregate $DB
execsql {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 SELECT a+2 FROM t1;
INSERT INTO t1 SELECT a+4 FROM t1;
INSERT INTO t1 SELECT a+8 FROM t1;
INSERT INTO t1 SELECT a+16 FROM t1;
INSERT INTO t1 SELECT a+32 FROM t1 ORDER BY a LIMIT 7;
SELECT x_count(*) FROM t1;
}
} {39}
do_test aggerror-1.2 {
execsql {
INSERT INTO t1 VALUES(40);
SELECT x_count(*) FROM t1;
}
} {40}
do_test aggerror-1.3 {
catchsql {
SELECT x_count(a) FROM t1;
}
} {1 {value of 40 handed to x_count}}
ifcapable utf16 {
do_test aggerror-1.4 {
execsql {
UPDATE t1 SET a=41 WHERE a=40
}
catchsql {
SELECT x_count(a) FROM t1;
}
} {1 abc}
}
do_test aggerror-1.5 {
execsql {
SELECT x_count(*) FROM t1
}
} 40
do_test aggerror-1.6 {
execsql {
INSERT INTO t1 VALUES(40);
INSERT INTO t1 VALUES(42);
}
catchsql {
SELECT x_count(*) FROM t1;
}
} {1 {x_count totals to 42}}
finish_test
+140
View File
@@ -0,0 +1,140 @@
# 2001 September 15
#
# 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 runs all tests.
#
# $Id: all.test,v 1.35 2006/01/17 15:36:33 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}
if {[file exists ./sqlite_test_count]} {
set COUNT [exec cat ./sqlite_test_count]
} else {
set COUNT 3
}
if {[llength $argv]>0} {
foreach {name value} $argv {
switch -- $name {
-count {
set COUNT $value
}
-quick {
set ISQUICK $value
}
default {
puts stderr "Unknown option: $name"
exit
}
}
}
}
set argv {}
# LeakList will hold a list of the number of unfreed mallocs after
# each round of the test. This number should be constant. If it
# grows, it may mean there is a memory leak in the library.
#
set LeakList {}
set EXCLUDE {
all.test
async.test
crash.test
autovacuum_crash.test
quick.test
malloc.test
misuse.test
memleak.test
}
# Files to include in the test. If this list is empty then everything
# that is not in the EXCLUDE list is run.
#
set INCLUDE {
}
# Test files btree2.test and btree4.test don't work if the
# SQLITE_DEFAULT_AUTOVACUUM macro is defined to true (because they depend
# on tables being allocated starting at page 2).
#
ifcapable default_autovacuum {
lappend EXCLUDE btree2.test
lappend EXCLUDE btree4.test
}
for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} {
if {$Counter%2} {
set ::SETUP_SQL {PRAGMA default_synchronous=off;}
} else {
catch {unset ::SETUP_SQL}
}
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
set tail [file tail $testfile]
if {[lsearch -exact $EXCLUDE $tail]>=0} continue
if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue
source $testfile
catch {db close}
if {$sqlite_open_file_count>0} {
puts "$tail did not close all files: $sqlite_open_file_count"
incr nErr
lappend ::failList $tail
}
}
if {[info exists Leak]} {
lappend LeakList $Leak
}
}
# Do one last test to look for a memory leak in the library. This will
# only work if SQLite is compiled with the -DSQLITE_DEBUG=1 flag.
#
if {$LeakList!=""} {
puts -nonewline memory-leak-test...
incr ::nTest
foreach x $LeakList {
if {$x!=[lindex $LeakList 0]} {
puts " failed!"
puts "Expected: all values to be the same"
puts " Got: $LeakList"
incr ::nErr
lappend ::failList memory-leak-test
break
}
}
puts " Ok"
}
# Run the crashtest only on unix and only once. If the library does not
# always create auto-vacuum databases, also run autovacuum_crash.test.
#
if {$::tcl_platform(platform)=="unix"} {
source $testdir/crash.test
ifcapable !default_autovacuum {
source $testdir/autovacuum_crash.test
}
}
# Run the malloc tests and the misuse test after memory leak detection.
# Both tests leak memory. Currently, misuse.test also leaks a handful of
# file descriptors. This is not considered a problem, but can cause tests
# in malloc.test to fail. So set the open-file count to zero before running
# malloc.test to get around this.
#
catch {source $testdir/misuse.test}
set sqlite_open_file_count 0
catch {source $testdir/malloc.test}
catch {db close}
set sqlite_open_file_count 0
really_finish_test
+634
View File
@@ -0,0 +1,634 @@
# 2004 November 10
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the ALTER TABLE statement.
#
# $Id: alter.test,v 1.17 2006/02/09 02:56:03 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
#----------------------------------------------------------------------
# Test organization:
#
# alter-1.1.* - alter-1.7.*: Basic tests of ALTER TABLE, including tables
# with implicit and explicit indices. These tests came from an earlier
# fork of SQLite that also supported ALTER TABLE.
# alter-1.8.*: Tests for ALTER TABLE when the table resides in an
# attached database.
# alter-1.9.*: Tests for ALTER TABLE when their is whitespace between the
# table name and left parenthesis token. i.e:
# "CREATE TABLE abc (a, b, c);"
# alter-2.*: Test error conditions and messages.
# alter-3.*: Test ALTER TABLE on tables that have TRIGGERs attached to them.
# alter-4.*: Test ALTER TABLE on tables that have AUTOINCREMENT fields.
#
# Create some tables to rename. Be sure to include some TEMP tables
# and some tables with odd names.
#
do_test alter-1.1 {
ifcapable tempdb {
set ::temp TEMP
} else {
set ::temp {}
}
execsql [subst -nocommands {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,2);
CREATE TABLE [t1'x1](c UNIQUE, b PRIMARY KEY);
INSERT INTO [t1'x1] VALUES(3,4);
CREATE INDEX t1i1 ON T1(B);
CREATE INDEX t1i2 ON t1(a,b);
CREATE INDEX i3 ON [t1'x1](b,c);
CREATE $::temp TABLE "temp table"(e,f,g UNIQUE);
CREATE INDEX i2 ON [temp table](f);
INSERT INTO [temp table] VALUES(5,6,7);
}]
execsql {
SELECT 't1', * FROM t1;
SELECT 't1''x1', * FROM "t1'x1";
SELECT * FROM [temp table];
}
} {t1 1 2 t1'x1 3 4 5 6 7}
do_test alter-1.2 {
execsql [subst {
CREATE $::temp TABLE objlist(type, name, tbl_name);
INSERT INTO objlist SELECT type, name, tbl_name
FROM sqlite_master WHERE NAME!='objlist';
}]
ifcapable tempdb {
execsql {
INSERT INTO objlist SELECT type, name, tbl_name
FROM sqlite_temp_master WHERE NAME!='objlist';
}
}
execsql {
SELECT type, name, tbl_name FROM objlist ORDER BY tbl_name, type desc, name;
}
} [list \
table t1 t1 \
index t1i1 t1 \
index t1i2 t1 \
table t1'x1 t1'x1 \
index i3 t1'x1 \
index {sqlite_autoindex_t1'x1_1} t1'x1 \
index {sqlite_autoindex_t1'x1_2} t1'x1 \
table {temp table} {temp table} \
index i2 {temp table} \
index {sqlite_autoindex_temp table_1} {temp table} \
]
# Make some changes
#
do_test alter-1.3 {
execsql {
ALTER TABLE [T1] RENAME to [-t1-];
ALTER TABLE "t1'x1" RENAME TO T2;
ALTER TABLE [temp table] RENAME to TempTab;
}
} {}
integrity_check alter-1.3.1
do_test alter-1.4 {
execsql {
SELECT 't1', * FROM [-t1-];
SELECT 't2', * FROM t2;
SELECT * FROM temptab;
}
} {t1 1 2 t2 3 4 5 6 7}
do_test alter-1.5 {
execsql {
DELETE FROM objlist;
INSERT INTO objlist SELECT type, name, tbl_name
FROM sqlite_master WHERE NAME!='objlist';
}
catchsql {
INSERT INTO objlist SELECT type, name, tbl_name
FROM sqlite_temp_master WHERE NAME!='objlist';
}
execsql {
SELECT type, name, tbl_name FROM objlist ORDER BY tbl_name, type desc, name;
}
} [list \
table -t1- -t1- \
index t1i1 -t1- \
index t1i2 -t1- \
table T2 T2 \
index i3 T2 \
index {sqlite_autoindex_T2_1} T2 \
index {sqlite_autoindex_T2_2} T2 \
table {TempTab} {TempTab} \
index i2 {TempTab} \
index {sqlite_autoindex_TempTab_1} {TempTab} \
]
# Make sure the changes persist after restarting the database.
# (The TEMP table will not persist, of course.)
#
ifcapable tempdb {
do_test alter-1.6 {
db close
sqlite3 db test.db
set DB [sqlite3_connection_pointer db]
execsql {
CREATE TEMP TABLE objlist(type, name, tbl_name);
INSERT INTO objlist SELECT type, name, tbl_name FROM sqlite_master;
INSERT INTO objlist
SELECT type, name, tbl_name FROM sqlite_temp_master
WHERE NAME!='objlist';
SELECT type, name, tbl_name FROM objlist
ORDER BY tbl_name, type desc, name;
}
} [list \
table -t1- -t1- \
index t1i1 -t1- \
index t1i2 -t1- \
table T2 T2 \
index i3 T2 \
index {sqlite_autoindex_T2_1} T2 \
index {sqlite_autoindex_T2_2} T2 \
]
} else {
execsql {
DROP TABLE TempTab;
}
}
# Make sure the ALTER TABLE statements work with the
# non-callback API
#
do_test alter-1.7 {
stepsql $DB {
ALTER TABLE [-t1-] RENAME to [*t1*];
ALTER TABLE T2 RENAME TO [<t2>];
}
execsql {
DELETE FROM objlist;
INSERT INTO objlist SELECT type, name, tbl_name
FROM sqlite_master WHERE NAME!='objlist';
}
catchsql {
INSERT INTO objlist SELECT type, name, tbl_name
FROM sqlite_temp_master WHERE NAME!='objlist';
}
execsql {
SELECT type, name, tbl_name FROM objlist ORDER BY tbl_name, type desc, name;
}
} [list \
table *t1* *t1* \
index t1i1 *t1* \
index t1i2 *t1* \
table <t2> <t2> \
index i3 <t2> \
index {sqlite_autoindex_<t2>_1} <t2> \
index {sqlite_autoindex_<t2>_2} <t2> \
]
# Check that ALTER TABLE works on attached databases.
#
do_test alter-1.8.1 {
file delete -force test2.db
file delete -force test2.db-journal
execsql {
ATTACH 'test2.db' AS aux;
}
} {}
do_test alter-1.8.2 {
execsql {
CREATE TABLE t4(a PRIMARY KEY, b, c);
CREATE TABLE aux.t4(a PRIMARY KEY, b, c);
CREATE INDEX i4 ON t4(b);
CREATE INDEX aux.i4 ON t4(b);
}
} {}
do_test alter-1.8.3 {
execsql {
INSERT INTO t4 VALUES('main', 'main', 'main');
INSERT INTO aux.t4 VALUES('aux', 'aux', 'aux');
SELECT * FROM t4 WHERE a = 'main';
}
} {main main main}
do_test alter-1.8.4 {
execsql {
ALTER TABLE t4 RENAME TO t5;
SELECT * FROM t4 WHERE a = 'aux';
}
} {aux aux aux}
do_test alter-1.8.5 {
execsql {
SELECT * FROM t5;
}
} {main main main}
do_test alter-1.8.6 {
execsql {
SELECT * FROM t5 WHERE b = 'main';
}
} {main main main}
do_test alter-1.8.7 {
execsql {
ALTER TABLE aux.t4 RENAME TO t5;
SELECT * FROM aux.t5 WHERE b = 'aux';
}
} {aux aux aux}
do_test alter-1.9.1 {
execsql {
CREATE TABLE tbl1 (a, b, c);
INSERT INTO tbl1 VALUES(1, 2, 3);
}
} {}
do_test alter-1.9.2 {
execsql {
SELECT * FROM tbl1;
}
} {1 2 3}
do_test alter-1.9.3 {
execsql {
ALTER TABLE tbl1 RENAME TO tbl2;
SELECT * FROM tbl2;
}
} {1 2 3}
do_test alter-1.9.4 {
execsql {
DROP TABLE tbl2;
}
} {}
# Test error messages
#
do_test alter-2.1 {
catchsql {
ALTER TABLE none RENAME TO hi;
}
} {1 {no such table: none}}
do_test alter-2.2 {
execsql {
CREATE TABLE t3(p,q,r);
}
catchsql {
ALTER TABLE [<t2>] RENAME TO t3;
}
} {1 {there is already another table or index with this name: t3}}
do_test alter-2.3 {
catchsql {
ALTER TABLE [<t2>] RENAME TO i3;
}
} {1 {there is already another table or index with this name: i3}}
do_test alter-2.4 {
catchsql {
ALTER TABLE SqLiTe_master RENAME TO master;
}
} {1 {table sqlite_master may not be altered}}
do_test alter-2.5 {
catchsql {
ALTER TABLE t3 RENAME TO sqlite_t3;
}
} {1 {object name reserved for internal use: sqlite_t3}}
# If this compilation does not include triggers, omit the alter-3.* tests.
ifcapable trigger {
#-----------------------------------------------------------------------
# Tests alter-3.* test ALTER TABLE on tables that have triggers.
#
# alter-3.1.*: ALTER TABLE with triggers.
# alter-3.2.*: Test that the ON keyword cannot be used as a database,
# table or column name unquoted. This is done because part of the
# ALTER TABLE code (specifically the implementation of SQL function
# "sqlite_alter_trigger") will break in this case.
# alter-3.3.*: ALTER TABLE with TEMP triggers (todo).
#
# An SQL user-function for triggers to fire, so that we know they
# are working.
proc trigfunc {args} {
set ::TRIGGER $args
}
db func trigfunc trigfunc
do_test alter-3.1.0 {
execsql {
CREATE TABLE t6(a, b, c);
CREATE TRIGGER trig1 AFTER INSERT ON t6 BEGIN
SELECT trigfunc('trig1', new.a, new.b, new.c);
END;
}
} {}
do_test alter-3.1.1 {
execsql {
INSERT INTO t6 VALUES(1, 2, 3);
}
set ::TRIGGER
} {trig1 1 2 3}
do_test alter-3.1.2 {
execsql {
ALTER TABLE t6 RENAME TO t7;
INSERT INTO t7 VALUES(4, 5, 6);
}
set ::TRIGGER
} {trig1 4 5 6}
do_test alter-3.1.3 {
execsql {
DROP TRIGGER trig1;
}
} {}
do_test alter-3.1.4 {
execsql {
CREATE TRIGGER trig2 AFTER INSERT ON main.t7 BEGIN
SELECT trigfunc('trig2', new.a, new.b, new.c);
END;
INSERT INTO t7 VALUES(1, 2, 3);
}
set ::TRIGGER
} {trig2 1 2 3}
do_test alter-3.1.5 {
execsql {
ALTER TABLE t7 RENAME TO t8;
INSERT INTO t8 VALUES(4, 5, 6);
}
set ::TRIGGER
} {trig2 4 5 6}
do_test alter-3.1.6 {
execsql {
DROP TRIGGER trig2;
}
} {}
do_test alter-3.1.7 {
execsql {
CREATE TRIGGER trig3 AFTER INSERT ON main.'t8'BEGIN
SELECT trigfunc('trig3', new.a, new.b, new.c);
END;
INSERT INTO t8 VALUES(1, 2, 3);
}
set ::TRIGGER
} {trig3 1 2 3}
do_test alter-3.1.8 {
execsql {
ALTER TABLE t8 RENAME TO t9;
INSERT INTO t9 VALUES(4, 5, 6);
}
set ::TRIGGER
} {trig3 4 5 6}
# Make sure "ON" cannot be used as a database, table or column name without
# quoting. Otherwise the sqlite_alter_trigger() function might not work.
file delete -force test3.db
file delete -force test3.db-journal
do_test alter-3.2.1 {
catchsql {
ATTACH 'test3.db' AS ON;
}
} {1 {near "ON": syntax error}}
do_test alter-3.2.2 {
catchsql {
ATTACH 'test3.db' AS 'ON';
}
} {0 {}}
do_test alter-3.2.3 {
catchsql {
CREATE TABLE ON.t1(a, b, c);
}
} {1 {near "ON": syntax error}}
do_test alter-3.2.4 {
catchsql {
CREATE TABLE 'ON'.t1(a, b, c);
}
} {0 {}}
do_test alter-3.2.4 {
catchsql {
CREATE TABLE 'ON'.ON(a, b, c);
}
} {1 {near "ON": syntax error}}
do_test alter-3.2.5 {
catchsql {
CREATE TABLE 'ON'.'ON'(a, b, c);
}
} {0 {}}
do_test alter-3.2.6 {
catchsql {
CREATE TABLE t10(a, ON, c);
}
} {1 {near "ON": syntax error}}
do_test alter-3.2.7 {
catchsql {
CREATE TABLE t10(a, 'ON', c);
}
} {0 {}}
do_test alter-3.2.8 {
catchsql {
CREATE TRIGGER trig4 AFTER INSERT ON ON BEGIN SELECT 1; END;
}
} {1 {near "ON": syntax error}}
do_test alter-3.2.9 {
catchsql {
CREATE TRIGGER 'on'.trig4 AFTER INSERT ON 'ON' BEGIN SELECT 1; END;
}
} {0 {}}
do_test alter-3.2.10 {
execsql {
DROP TABLE t10;
}
} {}
do_test alter-3.3.1 {
execsql [subst {
CREATE TABLE tbl1(a, b, c);
CREATE $::temp TRIGGER trig1 AFTER INSERT ON tbl1 BEGIN
SELECT trigfunc('trig1', new.a, new.b, new.c);
END;
}]
} {}
do_test alter-3.3.2 {
execsql {
INSERT INTO tbl1 VALUES('a', 'b', 'c');
}
set ::TRIGGER
} {trig1 a b c}
do_test alter-3.3.3 {
execsql {
ALTER TABLE tbl1 RENAME TO tbl2;
INSERT INTO tbl2 VALUES('d', 'e', 'f');
}
set ::TRIGGER
} {trig1 d e f}
do_test alter-3.3.4 {
execsql [subst {
CREATE $::temp TRIGGER trig2 AFTER UPDATE ON tbl2 BEGIN
SELECT trigfunc('trig2', new.a, new.b, new.c);
END;
}]
} {}
do_test alter-3.3.5 {
execsql {
ALTER TABLE tbl2 RENAME TO tbl3;
INSERT INTO tbl3 VALUES('g', 'h', 'i');
}
set ::TRIGGER
} {trig1 g h i}
do_test alter-3.3.6 {
execsql {
UPDATE tbl3 SET a = 'G' where a = 'g';
}
set ::TRIGGER
} {trig2 G h i}
do_test alter-3.3.7 {
execsql {
DROP TABLE tbl3;
}
} {}
ifcapable tempdb {
do_test alter-3.3.8 {
execsql {
SELECT * FROM sqlite_temp_master WHERE type = 'trigger';
}
} {}
}
} ;# ifcapable trigger
# If the build does not include AUTOINCREMENT fields, omit alter-4.*.
ifcapable autoinc {
do_test alter-4.1 {
execsql {
CREATE TABLE tbl1(a INTEGER PRIMARY KEY AUTOINCREMENT);
INSERT INTO tbl1 VALUES(10);
}
} {}
do_test alter-4.2 {
execsql {
INSERT INTO tbl1 VALUES(NULL);
SELECT a FROM tbl1;
}
} {10 11}
do_test alter-4.3 {
execsql {
ALTER TABLE tbl1 RENAME TO tbl2;
DELETE FROM tbl2;
INSERT INTO tbl2 VALUES(NULL);
SELECT a FROM tbl2;
}
} {12}
do_test alter-4.4 {
execsql {
DROP TABLE tbl2;
}
} {}
} ;# ifcapable autoinc
# Test that it is Ok to execute an ALTER TABLE immediately after
# opening a database.
do_test alter-5.1 {
execsql {
CREATE TABLE tbl1(a, b, c);
INSERT INTO tbl1 VALUES('x', 'y', 'z');
}
} {}
do_test alter-5.2 {
sqlite3 db2 test.db
execsql {
ALTER TABLE tbl1 RENAME TO tbl2;
SELECT * FROM tbl2;
} db2
} {x y z}
do_test alter-5.3 {
db2 close
} {}
foreach tblname [execsql {
SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite%'
}] {
execsql "DROP TABLE \"$tblname\""
}
set ::tbl_name "abc\uABCDdef"
do_test alter-6.1 {
string length $::tbl_name
} {7}
do_test alter-6.2 {
execsql "
CREATE TABLE ${tbl_name}(a, b, c);
"
set ::oid [execsql {SELECT max(oid) FROM sqlite_master}]
execsql "
SELECT sql FROM sqlite_master WHERE oid = $::oid;
"
} "{CREATE TABLE ${::tbl_name}(a, b, c)}"
execsql "
SELECT * FROM ${::tbl_name}
"
set ::tbl_name2 "abcXdef"
do_test alter-6.3 {
execsql "
ALTER TABLE $::tbl_name RENAME TO $::tbl_name2
"
execsql "
SELECT sql FROM sqlite_master WHERE oid = $::oid
"
} "{CREATE TABLE '${::tbl_name2}'(a, b, c)}"
do_test alter-6.4 {
execsql "
ALTER TABLE $::tbl_name2 RENAME TO $::tbl_name
"
execsql "
SELECT sql FROM sqlite_master WHERE oid = $::oid
"
} "{CREATE TABLE '${::tbl_name}'(a, b, c)}"
set ::col_name ghi\1234\jkl
do_test alter-6.5 {
execsql "
ALTER TABLE $::tbl_name ADD COLUMN $::col_name VARCHAR
"
execsql "
SELECT sql FROM sqlite_master WHERE oid = $::oid
"
} "{CREATE TABLE '${::tbl_name}'(a, b, c, $::col_name VARCHAR)}"
set ::col_name2 B\3421\A
do_test alter-6.6 {
db close
sqlite3 db test.db
execsql "
ALTER TABLE $::tbl_name ADD COLUMN $::col_name2
"
execsql "
SELECT sql FROM sqlite_master WHERE oid = $::oid
"
} "{CREATE TABLE '${::tbl_name}'(a, b, c, $::col_name VARCHAR, $::col_name2)}"
do_test alter-6.7 {
execsql "
INSERT INTO ${::tbl_name} VALUES(1, 2, 3, 4, 5);
SELECT $::col_name, $::col_name2 FROM $::tbl_name;
"
} {4 5}
# Ticket #1665: Make sure ALTER TABLE ADD COLUMN works on a table
# that includes a COLLATE clause.
#
do_test alter-7.1 {
execsql {
CREATE TABLE t1(a TEXT COLLATE BINARY);
ALTER TABLE t1 ADD COLUMN b INTEGER COLLATE NOCASE;
INSERT INTO t1 VALUES(1,'2');
SELECT typeof(a), a, typeof(b), b FROM t1;
}
} {text 1 integer 2}
finish_test
+438
View File
@@ -0,0 +1,438 @@
# 2005 February 18
#
# 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 regression tests for SQLite library. The
# focus of this script is testing that SQLite can handle a subtle
# file format change that may be used in the future to implement
# "ALTER TABLE ... ADD COLUMN".
#
# $Id: alter2.test,v 1.5 2006/01/03 00:33:50 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# We have to have pragmas in order to do this test
ifcapable {!pragma} return
# These tests do not work if there is a codec. The
# btree_open command does not know how to handle codecs.
#
if {[catch {sqlite3 -has_codec} r] || $r} return
# The file format change affects the way row-records stored in tables (but
# not indices) are interpreted. Before version 3.1.3, a row-record for a
# table with N columns was guaranteed to contain exactly N fields. As
# of version 3.1.3, the record may contain up to N fields. In this case
# the M fields that are present are the values for the left-most M
# columns. The (N-M) rightmost columns contain NULL.
#
# If any records in the database contain less fields than their table
# has columns, then the file-format meta value should be set to (at least) 2.
#
# This procedure sets the value of the file-format in file 'test.db'
# to $newval. Also, the schema cookie is incremented.
#
proc set_file_format {newval} {
set bt [btree_open test.db 10 0]
btree_begin_transaction $bt
set meta [btree_get_meta $bt]
lset meta 2 $newval ;# File format
lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie
eval "btree_update_meta $bt $meta"
btree_commit $bt
btree_close $bt
}
# This procedure returns the value of the file-format in file 'test.db'.
#
proc get_file_format {{fname test.db}} {
set bt [btree_open $fname 10 0]
set meta [btree_get_meta $bt]
btree_close $bt
lindex $meta 2
}
# This procedure sets the SQL statement stored for table $tbl in the
# sqlite_master table of file 'test.db' to $sql. Also set the file format
# to the supplied value. This is 2 if the added column has a default that is
# NULL, or 3 otherwise.
#
proc alter_table {tbl sql {file_format 2}} {
sqlite3 dbat test.db
puts one
dbat eval {
PRAGMA writable_schema = 1;
UPDATE sqlite_master SET sql = $sql WHERE name = $tbl AND type = 'table';
PRAGMA writable_schema = 0;
}
puts two
dbat close
puts three
set_file_format 2
puts four
}
#-----------------------------------------------------------------------
# Some basic tests to make sure short rows are handled.
#
do_test alter2-1.1 {
execsql {
CREATE TABLE abc(a, b);
INSERT INTO abc VALUES(1, 2);
INSERT INTO abc VALUES(3, 4);
INSERT INTO abc VALUES(5, 6);
}
} {}
do_test alter2-1.2 {
# ALTER TABLE abc ADD COLUMN c;
alter_table abc {CREATE TABLE abc(a, b, c);}
} {}
exit
do_test alter2-1.3 {
execsql {
SELECT * FROM abc;
}
} {1 2 {} 3 4 {} 5 6 {}}
do_test alter2-1.4 {
execsql {
UPDATE abc SET c = 10 WHERE a = 1;
SELECT * FROM abc;
}
} {1 2 10 3 4 {} 5 6 {}}
do_test alter2-1.5 {
execsql {
CREATE INDEX abc_i ON abc(c);
}
} {}
do_test alter2-1.6 {
execsql {
SELECT c FROM abc ORDER BY c;
}
} {{} {} 10}
do_test alter2-1.7 {
execsql {
SELECT * FROM abc WHERE c = 10;
}
} {1 2 10}
do_test alter2-1.8 {
execsql {
SELECT sum(a), c FROM abc GROUP BY c;
}
} {8.0 {} 1.0 10}
do_test alter2-1.9 {
# ALTER TABLE abc ADD COLUMN d;
alter_table abc {CREATE TABLE abc(a, b, c, d);}
execsql { SELECT * FROM abc; }
execsql {
UPDATE abc SET d = 11 WHERE c IS NULL AND a<4;
SELECT * FROM abc;
}
} {1 2 10 {} 3 4 {} 11 5 6 {} {}}
do_test alter2-1.10 {
execsql {
SELECT typeof(d) FROM abc;
}
} {null integer null}
do_test alter2-1.99 {
execsql {
DROP TABLE abc;
}
} {}
#-----------------------------------------------------------------------
# Test that views work when the underlying table structure is changed.
#
ifcapable view {
do_test alter2-2.1 {
execsql {
CREATE TABLE abc2(a, b, c);
INSERT INTO abc2 VALUES(1, 2, 10);
INSERT INTO abc2 VALUES(3, 4, NULL);
INSERT INTO abc2 VALUES(5, 6, NULL);
CREATE VIEW abc2_v AS SELECT * FROM abc2;
SELECT * FROM abc2_v;
}
} {1 2 10 3 4 {} 5 6 {}}
do_test alter2-2.2 {
# ALTER TABLE abc ADD COLUMN d;
alter_table abc2 {CREATE TABLE abc2(a, b, c, d);}
execsql {
SELECT * FROM abc2_v;
}
} {1 2 10 {} 3 4 {} {} 5 6 {} {}}
do_test alter2-2.3 {
execsql {
DROP TABLE abc2;
DROP VIEW abc2_v;
}
} {}
}
#-----------------------------------------------------------------------
# Test that triggers work when a short row is copied to the old.*
# trigger pseudo-table.
#
ifcapable trigger {
do_test alter2-3.1 {
execsql {
CREATE TABLE abc3(a, b);
CREATE TABLE blog(o, n);
CREATE TRIGGER abc3_t AFTER UPDATE OF b ON abc3 BEGIN
INSERT INTO blog VALUES(old.b, new.b);
END;
}
} {}
do_test alter2-3.2 {
execsql {
INSERT INTO abc3 VALUES(1, 4);
UPDATE abc3 SET b = 2 WHERE b = 4;
SELECT * FROM blog;
}
} {4 2}
do_test alter2-3.3 {
execsql {
INSERT INTO abc3 VALUES(3, 4);
INSERT INTO abc3 VALUES(5, 6);
}
alter_table abc3 {CREATE TABLE abc3(a, b, c);}
execsql {
SELECT * FROM abc3;
}
} {1 2 {} 3 4 {} 5 6 {}}
do_test alter2-3.4 {
execsql {
UPDATE abc3 SET b = b*2 WHERE a<4;
SELECT * FROM abc3;
}
} {1 4 {} 3 8 {} 5 6 {}}
do_test alter2-3.5 {
execsql {
SELECT * FROM blog;
}
} {4 2 2 4 4 8}
do_test alter2-3.6 {
execsql {
CREATE TABLE clog(o, n);
CREATE TRIGGER abc3_t2 AFTER UPDATE OF c ON abc3 BEGIN
INSERT INTO clog VALUES(old.c, new.c);
END;
UPDATE abc3 SET c = a*2;
SELECT * FROM clog;
}
} {{} 2 {} 6 {} 10}
}
#---------------------------------------------------------------------
# Check that an error occurs if the database is upgraded to a file
# format that SQLite does not support (in this case 4). Note: The
# file format is checked each time the schema is read, so changing the
# file format requires incrementing the schema cookie.
#
do_test alter2-4.1 {
set_file_format 4
} {}
do_test alter2-4.2 {
catchsql {
SELECT * FROM sqlite_master;
}
} {1 {unsupported file format}}
do_test alter2-4.3 {
sqlite3_errcode $::DB
} {SQLITE_ERROR}
do_test alter2-4.4 {
set ::DB [sqlite3_connection_pointer db]
catchsql {
SELECT * FROM sqlite_master;
}
} {1 {unsupported file format}}
do_test alter2-4.5 {
sqlite3_errcode $::DB
} {SQLITE_ERROR}
#---------------------------------------------------------------------
# Check that executing VACUUM on a file with file-format version 2
# resets the file format to 1.
#
do_test alter2-5.1 {
set_file_format 2
get_file_format
} {2}
do_test alter2-5.2 {
execsql {
VACUUM;
}
} {}
do_test alter2-5.3 {
get_file_format
} {1}
#---------------------------------------------------------------------
# Test that when a database with file-format 2 is opened, new
# databases are still created with file-format 1.
#
do_test alter2-6.1 {
db close
set_file_format 2
sqlite3 db test.db
set ::DB [sqlite3_connection_pointer db]
get_file_format
} {2}
do_test alter2-6.2 {
file delete -force test2.db-journal
file delete -force test2.db
execsql {
ATTACH 'test2.db' AS aux;
CREATE TABLE aux.t1(a, b);
}
get_file_format test2.db
} {1}
do_test alter2-6.3 {
execsql {
CREATE TABLE t1(a, b);
}
get_file_format
} {2}
#---------------------------------------------------------------------
# Test that types and values for columns added with default values
# other than NULL work with SELECT statements.
#
do_test alter2-7.1 {
execsql {
DROP TABLE t1;
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(3);
INSERT INTO t1 VALUES(4);
SELECT * FROM t1;
}
} {1 2 3 4}
do_test alter2-7.2 {
set sql {CREATE TABLE t1(a, b DEFAULT '123', c INTEGER DEFAULT '123')}
alter_table t1 $sql 3
execsql {
SELECT * FROM t1 LIMIT 1;
}
} {1 123 123}
do_test alter2-7.3 {
execsql {
SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;
}
} {1 integer 123 text 123 integer}
do_test alter2-7.4 {
execsql {
SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;
}
} {1 integer 123 text 123 integer}
do_test alter2-7.5 {
set sql {CREATE TABLE t1(a, b DEFAULT -123.0, c VARCHAR(10) default 5)}
alter_table t1 $sql 3
execsql {
SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;
}
} {1 integer -123.0 real 5 text}
#-----------------------------------------------------------------------
# Test that UPDATE trigger tables work with default values, and that when
# a row is updated the default values are correctly transfered to the
# new row.
#
ifcapable trigger {
db function set_val {set ::val}
do_test alter2-8.1 {
execsql {
CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN
SELECT set_val(
old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)||' '||
new.b||' '||typeof(new.b)||' '||new.c||' '||typeof(new.c)
);
END;
}
list
} {}
}
do_test alter2-8.2 {
execsql {
UPDATE t1 SET c = 10 WHERE a = 1;
SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;
}
} {1 integer -123.0 real 10 text}
ifcapable trigger {
do_test alter2-8.3 {
set ::val
} {-123 real 5 text -123 real 10 text}
}
#-----------------------------------------------------------------------
# Test that DELETE trigger tables work with default values, and that when
# a row is updated the default values are correctly transfered to the
# new row.
#
ifcapable trigger {
do_test alter2-9.1 {
execsql {
CREATE TRIGGER trig2 BEFORE DELETE ON t1 BEGIN
SELECT set_val(
old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)
);
END;
}
list
} {}
do_test alter2-9.2 {
execsql {
DELETE FROM t1 WHERE a = 2;
}
set ::val
} {-123 real 5 text}
}
#-----------------------------------------------------------------------
# Test creating an index on a column added with a default value.
#
do_test alter2-10.1 {
execsql {
CREATE TABLE t2(a);
INSERT INTO t2 VALUES('a');
INSERT INTO t2 VALUES('b');
INSERT INTO t2 VALUES('c');
INSERT INTO t2 VALUES('d');
}
alter_table t2 {CREATE TABLE t2(a, b DEFAULT X'ABCD', c DEFAULT NULL);} 3
catchsql {
SELECT * FROM sqlite_master;
}
execsql {
SELECT quote(a), quote(b), quote(c) FROM t2 LIMIT 1;
}
} {'a' X'ABCD' NULL}
do_test alter2-10.2 {
execsql {
CREATE INDEX i1 ON t2(b);
SELECT a FROM t2 WHERE b = X'ABCD';
}
} {a b c d}
do_test alter2-10.3 {
execsql {
DELETE FROM t2 WHERE a = 'c';
SELECT a FROM t2 WHERE b = X'ABCD';
}
} {a b d}
do_test alter2-10.4 {
execsql {
SELECT count(b) FROM t2 WHERE b = X'ABCD';
}
} {3}
finish_test
+396
View File
@@ -0,0 +1,396 @@
# 2005 February 19
#
# 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 regression tests for SQLite library. The
# focus of this script is testing that SQLite can handle a subtle
# file format change that may be used in the future to implement
# "ALTER TABLE ... ADD COLUMN".
#
# $Id: alter3.test,v 1.9 2006/01/17 09:35:02 danielk1977 Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
# Determine if there is a codec available on this test.
#
if {[catch {sqlite3 -has_codec} r] || $r} {
set has_codec 1
} else {
set has_codec 0
}
# Test Organisation:
# ------------------
#
# alter3-1.*: Test that ALTER TABLE correctly modifies the CREATE TABLE sql.
# alter3-2.*: Test error messages.
# alter3-3.*: Test adding columns with default value NULL.
# alter3-4.*: Test adding columns with default values other than NULL.
# alter3-5.*: Test adding columns to tables in ATTACHed databases.
# alter3-6.*: Test that temp triggers are not accidentally dropped.
# alter3-7.*: Test that VACUUM resets the file-format.
#
# This procedure returns the value of the file-format in file 'test.db'.
#
proc get_file_format {{fname test.db}} {
set bt [btree_open $fname 10 0]
set meta [btree_get_meta $bt]
btree_close $bt
lindex $meta 2
}
do_test alter3-1.1 {
execsql {
CREATE TABLE abc(a, b, c);
SELECT sql FROM sqlite_master;
}
} {{CREATE TABLE abc(a, b, c)}}
do_test alter3-1.2 {
execsql {ALTER TABLE abc ADD d INTEGER;}
execsql {
SELECT sql FROM sqlite_master;
}
} {{CREATE TABLE abc(a, b, c, d INTEGER)}}
do_test alter3-1.3 {
execsql {ALTER TABLE abc ADD e}
execsql {
SELECT sql FROM sqlite_master;
}
} {{CREATE TABLE abc(a, b, c, d INTEGER, e)}}
do_test alter3-1.4 {
execsql {
CREATE TABLE main.t1(a, b);
ALTER TABLE t1 ADD c;
SELECT sql FROM sqlite_master WHERE tbl_name = 't1';
}
} {{CREATE TABLE t1(a, b, c)}}
do_test alter3-1.5 {
execsql {
ALTER TABLE t1 ADD d CHECK (a>d);
SELECT sql FROM sqlite_master WHERE tbl_name = 't1';
}
} {{CREATE TABLE t1(a, b, c, d CHECK (a>d))}}
ifcapable foreignkey {
do_test alter3-1.6 {
execsql {
CREATE TABLE t2(a, b, UNIQUE(a, b));
ALTER TABLE t2 ADD c REFERENCES t1(c) ;
SELECT sql FROM sqlite_master WHERE tbl_name = 't2' AND type = 'table';
}
} {{CREATE TABLE t2(a, b, c REFERENCES t1(c), UNIQUE(a, b))}}
}
do_test alter3-1.7 {
execsql {
CREATE TABLE t3(a, b, UNIQUE(a, b));
ALTER TABLE t3 ADD COLUMN c VARCHAR(10, 20);
SELECT sql FROM sqlite_master WHERE tbl_name = 't3' AND type = 'table';
}
} {{CREATE TABLE t3(a, b, c VARCHAR(10, 20), UNIQUE(a, b))}}
do_test alter3-1.99 {
catchsql {
# May not exist if foriegn-keys are omitted at compile time.
DROP TABLE t2;
}
execsql {
DROP TABLE abc;
DROP TABLE t1;
DROP TABLE t3;
}
} {}
do_test alter3-2.1 {
execsql {
CREATE TABLE t1(a, b);
}
catchsql {
ALTER TABLE t1 ADD c PRIMARY KEY;
}
} {1 {Cannot add a PRIMARY KEY column}}
do_test alter3-2.2 {
catchsql {
ALTER TABLE t1 ADD c UNIQUE
}
} {1 {Cannot add a UNIQUE column}}
do_test alter3-2.3 {
catchsql {
ALTER TABLE t1 ADD b VARCHAR(10)
}
} {1 {duplicate column name: b}}
do_test alter3-2.3 {
catchsql {
ALTER TABLE t1 ADD c NOT NULL;
}
} {1 {Cannot add a NOT NULL column with default value NULL}}
do_test alter3-2.4 {
catchsql {
ALTER TABLE t1 ADD c NOT NULL DEFAULT 10;
}
} {0 {}}
ifcapable view {
do_test alter3-2.5 {
execsql {
CREATE VIEW v1 AS SELECT * FROM t1;
}
catchsql {
alter table v1 add column d;
}
} {1 {Cannot add a column to a view}}
}
do_test alter3-2.6 {
catchsql {
alter table t1 add column d DEFAULT CURRENT_TIME;
}
} {1 {Cannot add a column with non-constant default}}
do_test alter3-2.99 {
execsql {
DROP TABLE t1;
}
} {}
do_test alter3-3.1 {
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 100);
INSERT INTO t1 VALUES(2, 300);
SELECT * FROM t1;
}
} {1 100 2 300}
do_test alter3-3.1 {
execsql {
PRAGMA schema_version = 10;
}
} {}
do_test alter3-3.2 {
execsql {
ALTER TABLE t1 ADD c;
SELECT * FROM t1;
}
} {1 100 {} 2 300 {}}
if {!$has_codec} {
do_test alter3-3.3 {
get_file_format
} {3}
}
ifcapable schema_version {
do_test alter3-3.4 {
execsql {
PRAGMA schema_version;
}
} {11}
}
do_test alter3-4.1 {
db close
file delete -force test.db
set ::DB [sqlite3 db test.db]
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 100);
INSERT INTO t1 VALUES(2, 300);
SELECT * FROM t1;
}
} {1 100 2 300}
do_test alter3-4.1 {
execsql {
PRAGMA schema_version = 20;
}
} {}
do_test alter3-4.2 {
execsql {
ALTER TABLE t1 ADD c DEFAULT 'hello world';
SELECT * FROM t1;
}
} {1 100 {hello world} 2 300 {hello world}}
if {!$has_codec} {
do_test alter3-4.3 {
get_file_format
} {3}
}
ifcapable schema_version {
do_test alter3-4.4 {
execsql {
PRAGMA schema_version;
}
} {21}
}
do_test alter3-4.99 {
execsql {
DROP TABLE t1;
}
} {}
do_test alter3-5.1 {
file delete -force test2.db
file delete -force test2.db-journal
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
ATTACH 'test2.db' AS aux;
CREATE TABLE aux.t1 AS SELECT * FROM t1;
PRAGMA aux.schema_version = 30;
SELECT sql FROM aux.sqlite_master;
}
} {{CREATE TABLE t1(a,b)}}
do_test alter3-5.2 {
execsql {
ALTER TABLE aux.t1 ADD COLUMN c VARCHAR(128);
SELECT sql FROM aux.sqlite_master;
}
} {{CREATE TABLE t1(a,b, c VARCHAR(128))}}
do_test alter3-5.3 {
execsql {
SELECT * FROM aux.t1;
}
} {1 one {} 2 two {}}
ifcapable schema_version {
do_test alter3-5.4 {
execsql {
PRAGMA aux.schema_version;
}
} {31}
}
if {!$has_codec} {
do_test alter3-5.5 {
list [get_file_format test2.db] [get_file_format]
} {2 3}
}
do_test alter3-5.6 {
execsql {
ALTER TABLE aux.t1 ADD COLUMN d DEFAULT 1000;
SELECT sql FROM aux.sqlite_master;
}
} {{CREATE TABLE t1(a,b, c VARCHAR(128), d DEFAULT 1000)}}
do_test alter3-5.7 {
execsql {
SELECT * FROM aux.t1;
}
} {1 one {} 1000 2 two {} 1000}
ifcapable schema_version {
do_test alter3-5.8 {
execsql {
PRAGMA aux.schema_version;
}
} {32}
}
do_test alter3-5.9 {
execsql {
SELECT * FROM t1;
}
} {1 one 2 two}
do_test alter3-5.99 {
execsql {
DROP TABLE aux.t1;
DROP TABLE t1;
}
} {}
#----------------------------------------------------------------
# Test that the table schema is correctly reloaded when a column
# is added to a table.
#
ifcapable trigger&&tempdb {
do_test alter3-6.1 {
execsql {
CREATE TABLE t1(a, b);
CREATE TABLE log(trig, a, b);
CREATE TRIGGER t1_a AFTER INSERT ON t1 BEGIN
INSERT INTO log VALUES('a', new.a, new.b);
END;
CREATE TEMP TRIGGER t1_b AFTER INSERT ON t1 BEGIN
INSERT INTO log VALUES('b', new.a, new.b);
END;
INSERT INTO t1 VALUES(1, 2);
SELECT * FROM log;
}
} {b 1 2 a 1 2}
do_test alter3-6.2 {
execsql {
ALTER TABLE t1 ADD COLUMN c DEFAULT 'c';
INSERT INTO t1(a, b) VALUES(3, 4);
SELECT * FROM log;
}
} {b 1 2 a 1 2 b 3 4 a 3 4}
}
if {!$has_codec} {
ifcapable vacuum {
do_test alter3-7.1 {
execsql {
VACUUM;
}
get_file_format
} {1}
do_test alter3-7.2 {
execsql {
CREATE TABLE abc(a, b, c);
ALTER TABLE abc ADD d DEFAULT NULL;
}
get_file_format
} {2}
do_test alter3-7.3 {
execsql {
ALTER TABLE abc ADD e DEFAULT 10;
}
get_file_format
} {3}
do_test alter3-7.4 {
execsql {
ALTER TABLE abc ADD f DEFAULT NULL;
}
get_file_format
} {3}
do_test alter3-7.5 {
execsql {
VACUUM;
}
get_file_format
} {1}
}
}
# Ticket #1183 - Make sure adding columns to large tables does not cause
# memory corruption (as was the case before this bug was fixed).
do_test alter3-8.1 {
execsql {
CREATE TABLE t4(c1);
}
} {}
set ::sql ""
do_test alter3-8.2 {
set cols c1
for {set i 2} {$i < 100} {incr i} {
execsql "
ALTER TABLE t4 ADD c$i
"
lappend cols c$i
}
set ::sql "CREATE TABLE t4([join $cols {, }])"
list
} {}
do_test alter3-8.2 {
execsql {
SELECT sql FROM sqlite_master WHERE name = 't4';
}
} [list $::sql]
finish_test
+126
View File
@@ -0,0 +1,126 @@
# 2005 September 19
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the ALTER TABLE statement and
# specifically out-of-memory conditions within that command.
#
# $Id: altermalloc.test,v 1.3 2006/09/04 18:54:14 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if memory debugging is turned on.
#
if {[info command sqlite_malloc_stat]==""} {
puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG=1"
finish_test
return
}
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
# Usage: do_malloc_test <test name> <options...>
#
# The first argument, <test number>, is an integer used to name the
# tests executed by this proc. Options are as follows:
#
# -tclprep TCL script to run to prepare test.
# -sqlprep SQL script to run to prepare test.
# -tclbody TCL script to run with malloc failure simulation.
# -sqlbody TCL script to run with malloc failure simulation.
# -cleanup TCL script to run after the test.
#
# This command runs a series of tests to verify SQLite's ability
# to handle an out-of-memory condition gracefully. It is assumed
# that if this condition occurs a malloc() call will return a
# NULL pointer. Linux, for example, doesn't do that by default. See
# the "BUGS" section of malloc(3).
#
# Each iteration of a loop, the TCL commands in any argument passed
# to the -tclbody switch, followed by the SQL commands in any argument
# passed to the -sqlbody switch are executed. Each iteration the
# Nth call to sqliteMalloc() is made to fail, where N is increased
# each time the loop runs starting from 1. When all commands execute
# successfully, the loop ends.
#
proc do_malloc_test {tn args} {
array set ::mallocopts $args
set ::go 1
for {set ::n 1} {$::go} {incr ::n} {
do_test $tn.$::n {
sqlite_malloc_fail 0
catch {db close}
catch {file delete -force test.db}
catch {file delete -force test.db-journal}
catch {file delete -force test2.db}
catch {file delete -force test2.db-journal}
set ::DB [sqlite3 db test.db]
if {[info exists ::mallocopts(-tclprep)]} {
eval $::mallocopts(-tclprep)
}
if {[info exists ::mallocopts(-sqlprep)]} {
execsql $::mallocopts(-sqlprep)
}
sqlite_malloc_fail $::n
set ::mallocbody {}
if {[info exists ::mallocopts(-tclbody)]} {
append ::mallocbody "$::mallocopts(-tclbody)\n"
}
if {[info exists ::mallocopts(-sqlbody)]} {
append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
}
set v [catch $::mallocbody msg]
set leftover [lindex [sqlite_malloc_stat] 2]
if {$leftover>0} {
if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
set ::go 0
set v {1 1}
} else {
set v2 [expr {$msg=="" || $msg=="out of memory"}]
if {!$v2} {puts "\nError message returned: $msg"}
lappend v $v2
}
} {1 1}
sqlite_malloc_fail 0
if {[info exists ::mallocopts(-cleanup)]} {
catch $::mallocopts(-cleanup)
}
}
unset ::mallocopts
}
do_malloc_test altermalloc-1 -tclprep {
db close
} -tclbody {
if {[catch {sqlite3 db test.db}]} {
error "out of memory"
}
} -sqlbody {
CREATE TABLE t1(a int);
ALTER TABLE t1 ADD COLUMN b INTEGER DEFAULT NULL;
ALTER TABLE t1 ADD COLUMN c TEXT DEFAULT 'default-text';
ALTER TABLE t1 RENAME TO t2;
}
finish_test
+257
View File
@@ -0,0 +1,257 @@
# 2005 July 22
#
# 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 regression tests for SQLite library.
# This file implements tests for the ANALYZE command.
#
# $Id: analyze.test,v 1.5 2005/09/10 22:40:54 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# There is nothing to test if ANALYZE is disable for this build.
#
ifcapable {!analyze} {
finish_test
return
}
# Basic sanity checks.
#
do_test analyze-1.1 {
catchsql {
ANALYZE no_such_table
}
} {1 {no such table: no_such_table}}
do_test analyze-1.2 {
execsql {
SELECT count(*) FROM sqlite_master WHERE name='sqlite_stat1'
}
} {0}
do_test analyze-1.3 {
catchsql {
ANALYZE no_such_db.no_such_table
}
} {1 {unknown database no_such_db}}
do_test analyze-1.4 {
execsql {
SELECT count(*) FROM sqlite_master WHERE name='sqlite_stat1'
}
} {0}
do_test analyze-1.5.1 {
catchsql {
ANALYZE
}
} {0 {}}
do_test analyze-1.5.2 {
catchsql {
PRAGMA empty_result_callbacks=1;
ANALYZE
}
} {0 {}}
do_test analyze-1.6 {
execsql {
SELECT count(*) FROM sqlite_master WHERE name='sqlite_stat1'
}
} {1}
do_test analyze-1.7 {
execsql {
SELECT * FROM sqlite_stat1
}
} {}
do_test analyze-1.8 {
catchsql {
ANALYZE main
}
} {0 {}}
do_test analyze-1.9 {
execsql {
SELECT * FROM sqlite_stat1
}
} {}
do_test analyze-1.10 {
catchsql {
CREATE TABLE t1(a,b);
ANALYZE main.t1;
}
} {0 {}}
do_test analyze-1.11 {
execsql {
SELECT * FROM sqlite_stat1
}
} {}
do_test analyze-1.12 {
catchsql {
ANALYZE t1;
}
} {0 {}}
do_test analyze-1.13 {
execsql {
SELECT * FROM sqlite_stat1
}
} {}
# Create some indices that can be analyzed. But do not yet add
# data. Without data in the tables, no analysis is done.
#
do_test analyze-2.1 {
execsql {
CREATE INDEX t1i1 ON t1(a);
ANALYZE main.t1;
SELECT * FROM sqlite_stat1 ORDER BY idx;
}
} {}
do_test analyze-2.2 {
execsql {
CREATE INDEX t1i2 ON t1(b);
ANALYZE t1;
SELECT * FROM sqlite_stat1 ORDER BY idx;
}
} {}
do_test analyze-2.3 {
execsql {
CREATE INDEX t1i3 ON t1(a,b);
ANALYZE main;
SELECT * FROM sqlite_stat1 ORDER BY idx;
}
} {}
# Start adding data to the table. Verify that the analysis
# is done correctly.
#
do_test analyze-3.1 {
execsql {
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(1,3);
ANALYZE main.t1;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {2 2} t1i2 {2 1} t1i3 {2 2 1}}
do_test analyze-3.2 {
execsql {
INSERT INTO t1 VALUES(1,4);
INSERT INTO t1 VALUES(1,5);
ANALYZE t1;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {4 4} t1i2 {4 1} t1i3 {4 4 1}}
do_test analyze-3.3 {
execsql {
INSERT INTO t1 VALUES(2,5);
ANALYZE main;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {5 3} t1i2 {5 2} t1i3 {5 3 1}}
do_test analyze-3.4 {
execsql {
CREATE TABLE t2 AS SELECT * FROM t1;
CREATE INDEX t2i1 ON t2(a);
CREATE INDEX t2i2 ON t2(b);
CREATE INDEX t2i3 ON t2(a,b);
ANALYZE;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {5 3} t1i2 {5 2} t1i3 {5 3 1} t2i1 {5 3} t2i2 {5 2} t2i3 {5 3 1}}
do_test analyze-3.5 {
execsql {
DROP INDEX t2i3;
ANALYZE t1;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {5 3} t1i2 {5 2} t1i3 {5 3 1} t2i1 {5 3} t2i2 {5 2} t2i3 {5 3 1}}
do_test analyze-3.6 {
execsql {
ANALYZE t2;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {5 3} t1i2 {5 2} t1i3 {5 3 1} t2i1 {5 3} t2i2 {5 2}}
do_test analyze-3.7 {
execsql {
DROP INDEX t2i2;
ANALYZE t2;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t1i1 {5 3} t1i2 {5 2} t1i3 {5 3 1} t2i1 {5 3}}
do_test analyze-3.8 {
execsql {
CREATE TABLE t3 AS SELECT a, b, rowid AS c, 'hi' AS d FROM t1;
CREATE INDEX t3i1 ON t3(a);
CREATE INDEX t3i2 ON t3(a,b,c,d);
CREATE INDEX t3i3 ON t3(d,b,c,a);
DROP TABLE t1;
DROP TABLE t2;
ANALYZE;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t3i1 {5 3} t3i2 {5 3 1 1 1} t3i3 {5 5 2 1 1}}
# Try corrupting the sqlite_stat1 table and make sure the
# database is still able to function.
#
do_test analyze-4.0 {
sqlite3 db2 test.db
db2 eval {
CREATE TABLE t4(x,y,z);
CREATE INDEX t4i1 ON t4(x);
CREATE INDEX t4i2 ON t4(y);
INSERT INTO t4 SELECT a,b,c FROM t3;
}
db2 close
db close
sqlite3 db test.db
execsql {
ANALYZE;
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
}
} {t3i1 {5 3} t3i2 {5 3 1 1 1} t3i3 {5 5 2 1 1} t4i1 {5 3} t4i2 {5 2}}
do_test analyze-4.1 {
execsql {
PRAGMA writable_schema=on;
INSERT INTO sqlite_stat1 VALUES(null,null,null);
PRAGMA writable_schema=off;
}
db close
sqlite3 db test.db
execsql {
SELECT * FROM t4 WHERE x=1234;
}
} {}
do_test analyze-4.2 {
execsql {
PRAGMA writable_schema=on;
DELETE FROM sqlite_stat1;
INSERT INTO sqlite_stat1 VALUES('t4','t4i1','nonsense');
INSERT INTO sqlite_stat1 VALUES('t4','t4i2','120897349817238741092873198273409187234918720394817209384710928374109827172901827349871928741910');
PRAGMA writable_schema=off;
}
db close
sqlite3 db test.db
execsql {
SELECT * FROM t4 WHERE x=1234;
}
} {}
# This test corrupts the database file so it must be the last test
# in the series.
#
do_test analyze-99.1 {
execsql {
PRAGMA writable_schema=on;
UPDATE sqlite_master SET sql='nonsense';
}
db close
sqlite3 db test.db
catchsql {
ANALYZE
}
} {1 {malformed database schema - near "nonsense": syntax error}}
finish_test
+65
View File
@@ -0,0 +1,65 @@
#
# 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 runs all tests.
#
# $Id: async.test,v 1.7 2006/03/19 13:00:25 drh Exp $
if {[catch {sqlite3async_enable}]} {
# The async logic is not built into this system
return
}
set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {}
set ISQUICK 1
set INCLUDE {
select1.test
select2.test
select3.test
select4.test
insert.test
insert2.test
insert3.test
trans.test
}
# set INCLUDE {select4.test}
# Enable asynchronous IO.
sqlite3async_enable 1
rename do_test really_do_test
proc do_test {name args} {
uplevel really_do_test async_io-$name $args
sqlite3async_halt idle
sqlite3async_start
sqlite3async_wait
}
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
set tail [file tail $testfile]
if {[lsearch -exact $INCLUDE $tail]<0} continue
source $testfile
catch {db close}
}
# Flush the write-queue and disable asynchronous IO. This should ensure
# all allocated memory is cleaned up.
set sqlite3async_trace 1
sqlite3async_halt idle
sqlite3async_start
sqlite3async_wait
sqlite3async_enable 0
set sqlite3async_trace 0
really_finish_test
rename really_do_test do_test
rename really_finish_test finish_test
+119
View File
@@ -0,0 +1,119 @@
#
# 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.
#
#***********************************************************************
#
# $Id: async2.test,v 1.3 2006/02/14 14:02:08 danielk1977 Exp $
if {[info commands sqlite3async_enable]==""} {
# The async logic is not built into this system
return
}
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Enable asynchronous IO.
set setup_script {
CREATE TABLE counter(c);
INSERT INTO counter(c) VALUES (1);
}
set sql_script {
BEGIN;
UPDATE counter SET c = 2;
CREATE TABLE t1(a PRIMARY KEY, b, c);
CREATE TABLE t2(a PRIMARY KEY, b, c);
COMMIT;
BEGIN;
UPDATE counter SET c = 3;
INSERT INTO t1 VALUES('abcdefghij', 'four', 'score');
INSERT INTO t2 VALUES('klmnopqrst', 'and', 'seven');
COMMIT;
UPDATE counter SET c = 'FIN';
}
db close
foreach err [list ioerr malloc] {
set ::go 1
for {set n 1} {$::go} {incr n} {
set ::sqlite_io_error_pending 0
sqlite_malloc_fail 0
file delete -force test.db test.db-journal
sqlite3 db test.db
execsql $::setup_script
db close
sqlite3async_enable 1
sqlite3 db test.db
execsql $::sql_script
db close
switch -- $err {
ioerr { set ::sqlite_io_error_pending $n }
malloc { sqlite_malloc_fail $n }
}
sqlite3async_halt idle
sqlite3async_start
sqlite3async_wait
set ::sqlite_io_error_pending 0
sqlite_malloc_fail 0
sqlite3 db test.db
set c [db eval {SELECT c FROM counter LIMIT 1}]
switch -- $c {
1 {
do_test async-$err-1.1.$n {
execsql {
SELECT name FROM sqlite_master;
}
} {counter}
}
2 {
do_test async-$err-1.2.$n.1 {
execsql {
SELECT * FROM t1;
}
} {}
do_test async-$err-1.2.$n.2 {
execsql {
SELECT * FROM t2;
}
} {}
}
3 {
do_test async-$err-1.3.$n.1 {
execsql {
SELECT * FROM t1;
}
} {abcdefghij four score}
do_test async-$err-1.3.$n.2 {
execsql {
SELECT * FROM t2;
}
} {klmnopqrst and seven}
}
FIN {
set ::go 0
}
}
sqlite3async_enable 0
}
}
catch {db close}
sqlite3async_halt idle
sqlite3async_start
sqlite3async_wait
finish_test
+738
View File
@@ -0,0 +1,738 @@
# 2003 April 4
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach.test,v 1.43 2006/05/25 12:17:32 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
for {set i 2} {$i<=15} {incr i} {
file delete -force test$i.db
file delete -force test$i.db-journal
}
set btree_trace 0
do_test attach-1.1 {
execsql {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(3,4);
SELECT * FROM t1;
}
} {1 2 3 4}
do_test attach-1.2 {
sqlite3 db2 test2.db
execsql {
CREATE TABLE t2(x,y);
INSERT INTO t2 VALUES(1,'x');
INSERT INTO t2 VALUES(2,'y');
SELECT * FROM t2;
} db2
} {1 x 2 y}
do_test attach-1.3 {
execsql {
ATTACH DATABASE 'test2.db' AS two;
SELECT * FROM two.t2;
}
} {1 x 2 y}
do_test attach-1.4 {
execsql {
SELECT * FROM t2;
}
} {1 x 2 y}
do_test attach-1.5 {
execsql {
DETACH DATABASE two;
SELECT * FROM t1;
}
} {1 2 3 4}
do_test attach-1.6 {
catchsql {
SELECT * FROM t2;
}
} {1 {no such table: t2}}
do_test attach-1.7 {
catchsql {
SELECT * FROM two.t2;
}
} {1 {no such table: two.t2}}
do_test attach-1.8 {
catchsql {
ATTACH DATABASE 'test3.db' AS three;
}
} {0 {}}
do_test attach-1.9 {
catchsql {
SELECT * FROM three.sqlite_master;
}
} {0 {}}
do_test attach-1.10 {
catchsql {
DETACH DATABASE [three];
}
} {0 {}}
do_test attach-1.11 {
execsql {
ATTACH 'test.db' AS db2;
ATTACH 'test.db' AS db3;
ATTACH 'test.db' AS db4;
ATTACH 'test.db' AS db5;
ATTACH 'test.db' AS db6;
ATTACH 'test.db' AS db7;
ATTACH 'test.db' AS db8;
ATTACH 'test.db' AS db9;
}
} {}
proc db_list {db} {
set list {}
foreach {idx name file} [execsql {PRAGMA database_list} $db] {
lappend list $idx $name
}
return $list
}
ifcapable schema_pragmas {
do_test attach-1.11b {
db_list db
} {0 main 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9}
} ;# ifcapable schema_pragmas
do_test attach-1.12 {
catchsql {
ATTACH 'test.db' as db2;
}
} {1 {database db2 is already in use}}
do_test attach-1.13 {
catchsql {
ATTACH 'test.db' as db5;
}
} {1 {database db5 is already in use}}
do_test attach-1.14 {
catchsql {
ATTACH 'test.db' as db9;
}
} {1 {database db9 is already in use}}
do_test attach-1.15 {
catchsql {
ATTACH 'test.db' as main;
}
} {1 {database main is already in use}}
ifcapable tempdb {
do_test attach-1.16 {
catchsql {
ATTACH 'test.db' as temp;
}
} {1 {database temp is already in use}}
}
do_test attach-1.17 {
catchsql {
ATTACH 'test.db' as MAIN;
}
} {1 {database MAIN is already in use}}
do_test attach-1.18 {
catchsql {
ATTACH 'test.db' as db10;
ATTACH 'test.db' as db11;
}
} {0 {}}
do_test attach-1.19 {
catchsql {
ATTACH 'test.db' as db12;
}
} {1 {too many attached databases - max 10}}
do_test attach-1.20.1 {
execsql {
DETACH db5;
}
} {}
ifcapable schema_pragmas {
do_test attach-1.20.2 {
db_list db
} {0 main 2 db2 3 db3 4 db4 5 db6 6 db7 7 db8 8 db9 9 db10 10 db11}
} ;# ifcapable schema_pragmas
integrity_check attach-1.20.3
ifcapable tempdb {
execsql {select * from sqlite_temp_master}
}
do_test attach-1.21 {
catchsql {
ATTACH 'test.db' as db12;
}
} {0 {}}
do_test attach-1.22 {
catchsql {
ATTACH 'test.db' as db13;
}
} {1 {too many attached databases - max 10}}
do_test attach-1.23 {
catchsql {
DETACH "db14";
}
} {1 {no such database: db14}}
do_test attach-1.24 {
catchsql {
DETACH db12;
}
} {0 {}}
do_test attach-1.25 {
catchsql {
DETACH db12;
}
} {1 {no such database: db12}}
do_test attach-1.26 {
catchsql {
DETACH main;
}
} {1 {cannot detach database main}}
ifcapable tempdb {
do_test attach-1.27 {
catchsql {
DETACH Temp;
}
} {1 {cannot detach database Temp}}
} else {
do_test attach-1.27 {
catchsql {
DETACH Temp;
}
} {1 {no such database: Temp}}
}
do_test attach-1.28 {
catchsql {
DETACH db11;
DETACH db10;
DETACH db9;
DETACH db8;
DETACH db7;
DETACH db6;
DETACH db4;
DETACH db3;
DETACH db2;
}
} {0 {}}
ifcapable schema_pragmas {
ifcapable tempdb {
do_test attach-1.29 {
db_list db
} {0 main 1 temp}
} else {
do_test attach-1.29 {
db_list db
} {0 main}
}
} ;# ifcapable schema_pragmas
ifcapable {trigger} { # Only do the following tests if triggers are enabled
do_test attach-2.1 {
execsql {
CREATE TABLE tx(x1,x2,y1,y2);
CREATE TRIGGER r1 AFTER UPDATE ON t2 FOR EACH ROW BEGIN
INSERT INTO tx(x1,x2,y1,y2) VALUES(OLD.x,NEW.x,OLD.y,NEW.y);
END;
SELECT * FROM tx;
} db2;
} {}
do_test attach-2.2 {
execsql {
UPDATE t2 SET x=x+10;
SELECT * FROM tx;
} db2;
} {1 11 x x 2 12 y y}
do_test attach-2.3 {
execsql {
CREATE TABLE tx(x1,x2,y1,y2);
SELECT * FROM tx;
}
} {}
do_test attach-2.4 {
execsql {
ATTACH 'test2.db' AS db2;
}
} {}
do_test attach-2.5 {
execsql {
UPDATE db2.t2 SET x=x+10;
SELECT * FROM db2.tx;
}
} {1 11 x x 2 12 y y 11 21 x x 12 22 y y}
do_test attach-2.6 {
execsql {
SELECT * FROM main.tx;
}
} {}
do_test attach-2.7 {
execsql {
SELECT type, name, tbl_name FROM db2.sqlite_master;
}
} {table t2 t2 table tx tx trigger r1 t2}
ifcapable schema_pragmas&&tempdb {
do_test attach-2.8 {
db_list db
} {0 main 1 temp 2 db2}
} ;# ifcapable schema_pragmas&&tempdb
ifcapable schema_pragmas&&!tempdb {
do_test attach-2.8 {
db_list db
} {0 main 2 db2}
} ;# ifcapable schema_pragmas&&!tempdb
do_test attach-2.9 {
execsql {
CREATE INDEX i2 ON t2(x);
SELECT * FROM t2 WHERE x>5;
} db2
} {21 x 22 y}
do_test attach-2.10 {
execsql {
SELECT type, name, tbl_name FROM sqlite_master;
} db2
} {table t2 t2 table tx tx trigger r1 t2 index i2 t2}
#do_test attach-2.11 {
# catchsql {
# SELECT * FROM t2 WHERE x>5;
# }
#} {1 {database schema has changed}}
ifcapable schema_pragmas {
ifcapable tempdb {
do_test attach-2.12 {
db_list db
} {0 main 1 temp 2 db2}
} else {
do_test attach-2.12 {
db_list db
} {0 main 2 db2}
}
} ;# ifcapable schema_pragmas
do_test attach-2.13 {
catchsql {
SELECT * FROM t2 WHERE x>5;
}
} {0 {21 x 22 y}}
do_test attach-2.14 {
execsql {
SELECT type, name, tbl_name FROM sqlite_master;
}
} {table t1 t1 table tx tx}
do_test attach-2.15 {
execsql {
SELECT type, name, tbl_name FROM db2.sqlite_master;
}
} {table t2 t2 table tx tx trigger r1 t2 index i2 t2}
do_test attach-2.16 {
db close
sqlite3 db test.db
execsql {
ATTACH 'test2.db' AS db2;
SELECT type, name, tbl_name FROM db2.sqlite_master;
}
} {table t2 t2 table tx tx trigger r1 t2 index i2 t2}
} ;# End of ifcapable {trigger}
do_test attach-3.1 {
db close
db2 close
sqlite3 db test.db
sqlite3 db2 test2.db
execsql {
SELECT * FROM t1
}
} {1 2 3 4}
# If we are testing a version of the code that lacks trigger support,
# adjust the database contents so that they are the same if triggers
# had been enabled.
ifcapable {!trigger} {
db2 eval {
DELETE FROM t2;
INSERT INTO t2 VALUES(21, 'x');
INSERT INTO t2 VALUES(22, 'y');
CREATE TABLE tx(x1,x2,y1,y2);
INSERT INTO tx VALUES(1, 11, 'x', 'x');
INSERT INTO tx VALUES(2, 12, 'y', 'y');
INSERT INTO tx VALUES(11, 21, 'x', 'x');
INSERT INTO tx VALUES(12, 22, 'y', 'y');
CREATE INDEX i2 ON t2(x);
}
}
do_test attach-3.2 {
catchsql {
SELECT * FROM t2
}
} {1 {no such table: t2}}
do_test attach-3.3 {
catchsql {
ATTACH DATABASE 'test2.db' AS db2;
SELECT * FROM t2
}
} {0 {21 x 22 y}}
# Even though 'db' has started a transaction, it should not yet have
# a lock on test2.db so 'db2' should be readable.
do_test attach-3.4 {
execsql BEGIN
catchsql {
SELECT * FROM t2;
} db2;
} {0 {21 x 22 y}}
# Reading from test2.db from db within a transaction should not
# prevent test2.db from being read by db2.
do_test attach-3.5 {
execsql {SELECT * FROM t2}
btree_breakpoint
catchsql {
SELECT * FROM t2;
} db2;
} {0 {21 x 22 y}}
# Making a change to test2.db through db causes test2.db to get
# a reserved lock. It should still be accessible through db2.
do_test attach-3.6 {
execsql {
UPDATE t2 SET x=x+1 WHERE x=50;
}
catchsql {
SELECT * FROM t2;
} db2;
} {0 {21 x 22 y}}
do_test attach-3.7 {
execsql ROLLBACK
execsql {SELECT * FROM t2} db2
} {21 x 22 y}
# Start transactions on both db and db2. Once again, just because
# we make a change to test2.db using db2, only a RESERVED lock is
# obtained, so test2.db should still be readable using db.
#
do_test attach-3.8 {
execsql BEGIN
execsql BEGIN db2
execsql {UPDATE t2 SET x=0 WHERE 0} db2
catchsql {SELECT * FROM t2}
} {0 {21 x 22 y}}
# It is also still accessible from db2.
do_test attach-3.9 {
catchsql {SELECT * FROM t2} db2
} {0 {21 x 22 y}}
do_test attach-3.10 {
execsql {SELECT * FROM t1}
} {1 2 3 4}
do_test attach-3.11 {
catchsql {UPDATE t1 SET a=a+1}
} {0 {}}
do_test attach-3.12 {
execsql {SELECT * FROM t1}
} {2 2 4 4}
# db2 has a RESERVED lock on test2.db, so db cannot write to any tables
# in test2.db.
do_test attach-3.13 {
catchsql {UPDATE t2 SET x=x+1 WHERE x=50}
} {1 {database is locked}}
# Change for version 3. Transaction is no longer rolled back
# for a locked database.
execsql {ROLLBACK}
# db is able to reread its schema because db2 still only holds a
# reserved lock.
do_test attach-3.14 {
catchsql {SELECT * FROM t1}
} {0 {1 2 3 4}}
do_test attach-3.15 {
execsql COMMIT db2
execsql {SELECT * FROM t1}
} {1 2 3 4}
#set btree_trace 1
# Ticket #323
do_test attach-4.1 {
execsql {DETACH db2}
db2 close
sqlite3 db2 test2.db
execsql {
CREATE TABLE t3(x,y);
CREATE UNIQUE INDEX t3i1 ON t3(x);
INSERT INTO t3 VALUES(1,2);
SELECT * FROM t3;
} db2;
} {1 2}
do_test attach-4.2 {
execsql {
CREATE TABLE t3(a,b);
CREATE UNIQUE INDEX t3i1b ON t3(a);
INSERT INTO t3 VALUES(9,10);
SELECT * FROM t3;
}
} {9 10}
do_test attach-4.3 {
execsql {
ATTACH DATABASE 'test2.db' AS db2;
SELECT * FROM db2.t3;
}
} {1 2}
do_test attach-4.4 {
execsql {
SELECT * FROM main.t3;
}
} {9 10}
do_test attach-4.5 {
execsql {
INSERT INTO db2.t3 VALUES(9,10);
SELECT * FROM db2.t3;
}
} {1 2 9 10}
execsql {
DETACH db2;
}
ifcapable {trigger} {
do_test attach-4.6 {
execsql {
CREATE TABLE t4(x);
CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN
INSERT INTO t4 VALUES('db2.' || NEW.x);
END;
INSERT INTO t3 VALUES(6,7);
SELECT * FROM t4;
} db2
} {db2.6}
do_test attach-4.7 {
execsql {
CREATE TABLE t4(y);
CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN
INSERT INTO t4 VALUES('main.' || NEW.a);
END;
INSERT INTO main.t3 VALUES(11,12);
SELECT * FROM main.t4;
}
} {main.11}
}
ifcapable {!trigger} {
# When we do not have trigger support, set up the table like they
# would have been had triggers been there. The tests that follow need
# this setup.
execsql {
CREATE TABLE t4(x);
INSERT INTO t3 VALUES(6,7);
INSERT INTO t4 VALUES('db2.6');
INSERT INTO t4 VALUES('db2.13');
} db2
execsql {
CREATE TABLE t4(y);
INSERT INTO main.t3 VALUES(11,12);
INSERT INTO t4 VALUES('main.11');
}
}
# This one is tricky. On the UNION ALL select, we have to make sure
# the schema for both main and db2 is valid before starting to execute
# the first query of the UNION ALL. If we wait to test the validity of
# the schema for main until after the first query has run, that test will
# fail and the query will abort but we will have already output some
# results. When the query is retried, the results will be repeated.
#
ifcapable compound {
do_test attach-4.8 {
execsql {
ATTACH DATABASE 'test2.db' AS db2;
INSERT INTO db2.t3 VALUES(13,14);
SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
}
} {db2.6 db2.13 main.11}
do_test attach-4.9 {
ifcapable {!trigger} {execsql {INSERT INTO main.t4 VALUES('main.15')}}
execsql {
INSERT INTO main.t3 VALUES(15,16);
SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
}
} {db2.6 db2.13 main.11 main.15}
} ;# ifcapable compound
ifcapable !compound {
ifcapable {!trigger} {execsql {INSERT INTO main.t4 VALUES('main.15')}}
execsql {
ATTACH DATABASE 'test2.db' AS db2;
INSERT INTO db2.t3 VALUES(13,14);
INSERT INTO main.t3 VALUES(15,16);
}
} ;# ifcapable !compound
ifcapable view {
do_test attach-4.10 {
execsql {
DETACH DATABASE db2;
}
execsql {
CREATE VIEW v3 AS SELECT x*100+y FROM t3;
SELECT * FROM v3;
} db2
} {102 910 607 1314}
do_test attach-4.11 {
execsql {
CREATE VIEW v3 AS SELECT a*100+b FROM t3;
SELECT * FROM v3;
}
} {910 1112 1516}
do_test attach-4.12 {
execsql {
ATTACH DATABASE 'test2.db' AS db2;
SELECT * FROM db2.v3;
}
} {102 910 607 1314}
do_test attach-4.13 {
execsql {
SELECT * FROM main.v3;
}
} {910 1112 1516}
} ;# ifcapable view
# Tests for the sqliteFix...() routines in attach.c
#
ifcapable {trigger} {
do_test attach-5.1 {
db close
sqlite3 db test.db
db2 close
file delete -force test2.db
sqlite3 db2 test2.db
catchsql {
ATTACH DATABASE 'test.db' AS orig;
CREATE TRIGGER r1 AFTER INSERT ON orig.t1 BEGIN
SELECT 'no-op';
END;
} db2
} {1 {trigger r1 cannot reference objects in database orig}}
do_test attach-5.2 {
catchsql {
CREATE TABLE t5(x,y);
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT 'no-op';
END;
} db2
} {0 {}}
do_test attach-5.3 {
catchsql {
DROP TRIGGER r5;
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT 'no-op' FROM orig.t1;
END;
} db2
} {1 {trigger r5 cannot reference objects in database orig}}
ifcapable tempdb {
do_test attach-5.4 {
catchsql {
CREATE TEMP TABLE t6(p,q,r);
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT 'no-op' FROM temp.t6;
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
}
ifcapable subquery {
do_test attach-5.5 {
catchsql {
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT 'no-op' || (SELECT * FROM temp.t6);
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
do_test attach-5.6 {
catchsql {
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT 'no-op' FROM t1 WHERE x<(SELECT min(x) FROM temp.t6);
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
do_test attach-5.7 {
catchsql {
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT 'no-op' FROM t1 GROUP BY 1 HAVING x<(SELECT min(x) FROM temp.t6);
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
do_test attach-5.7 {
catchsql {
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
SELECT max(1,x,(SELECT min(x) FROM temp.t6)) FROM t1;
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
do_test attach-5.8 {
catchsql {
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
INSERT INTO t1 VALUES((SELECT min(x) FROM temp.t6),5);
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
do_test attach-5.9 {
catchsql {
CREATE TRIGGER r5 AFTER INSERT ON t5 BEGIN
DELETE FROM t1 WHERE x<(SELECT min(x) FROM temp.t6);
END;
} db2
} {1 {trigger r5 cannot reference objects in database temp}}
} ;# endif subquery
} ;# endif trigger
# Check to make sure we get a sensible error if unable to open
# the file that we are trying to attach.
#
do_test attach-6.1 {
catchsql {
ATTACH DATABASE 'no-such-file' AS nosuch;
}
} {0 {}}
if {$tcl_platform(platform)=="unix"} {
do_test attach-6.2 {
sqlite3 dbx cannot-read
dbx eval {CREATE TABLE t1(a,b,c)}
dbx close
file attributes cannot-read -permission 0000
if {[file writable cannot-read]} {
puts "\n**** Tests do not work when run as root ****"
file delete -force cannot-read
exit 1
}
catchsql {
ATTACH DATABASE 'cannot-read' AS noread;
}
} {1 {unable to open database: cannot-read}}
file delete -force cannot-read
}
# Check the error message if we try to access a database that has
# not been attached.
do_test attach-6.3 {
catchsql {
CREATE TABLE no_such_db.t1(a, b, c);
}
} {1 {unknown database no_such_db}}
for {set i 2} {$i<=15} {incr i} {
catch {db$i close}
}
db close
file delete -force test2.db
file delete -force no-such-file
finish_test
+379
View File
@@ -0,0 +1,379 @@
# 2003 July 1
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.35 2006/01/03 00:33:50 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Ticket #354
#
# Databases test.db and test2.db contain identical schemas. Make
# sure we can attach test2.db from test.db.
#
do_test attach2-1.1 {
db eval {
CREATE TABLE t1(a,b);
CREATE INDEX x1 ON t1(a);
}
file delete -force test2.db
file delete -force test2.db-journal
sqlite3 db2 test2.db
db2 eval {
CREATE TABLE t1(a,b);
CREATE INDEX x1 ON t1(a);
}
catchsql {
ATTACH 'test2.db' AS t2;
}
} {0 {}}
# Ticket #514
#
proc db_list {db} {
set list {}
foreach {idx name file} [execsql {PRAGMA database_list} $db] {
lappend list $idx $name
}
return $list
}
db eval {DETACH t2}
do_test attach2-2.1 {
# lock test2.db then try to attach it. This is no longer an error because
# db2 just RESERVES the database. It does not obtain a write-lock until
# we COMMIT.
db2 eval {BEGIN}
db2 eval {UPDATE t1 SET a = 0 WHERE 0}
catchsql {
ATTACH 'test2.db' AS t2;
}
} {0 {}}
ifcapable schema_pragmas {
do_test attach2-2.2 {
# make sure test2.db did get attached.
db_list db
} {0 main 2 t2}
} ;# ifcapable schema_pragmas
db2 eval {COMMIT}
do_test attach2-2.5 {
# Make sure we can read test2.db from db
catchsql {
SELECT name FROM t2.sqlite_master;
}
} {0 {t1 x1}}
do_test attach2-2.6 {
# lock test2.db and try to read from it. This should still work because
# the lock is only a RESERVED lock which does not prevent reading.
#
db2 eval BEGIN
db2 eval {UPDATE t1 SET a = 0 WHERE 0}
catchsql {
SELECT name FROM t2.sqlite_master;
}
} {0 {t1 x1}}
do_test attach2-2.7 {
# but we can still read from test1.db even though test2.db is locked.
catchsql {
SELECT name FROM main.sqlite_master;
}
} {0 {t1 x1}}
do_test attach2-2.8 {
# start a transaction on test.db even though test2.db is locked.
catchsql {
BEGIN;
INSERT INTO t1 VALUES(8,9);
}
} {0 {}}
do_test attach2-2.9 {
execsql {
SELECT * FROM t1
}
} {8 9}
do_test attach2-2.10 {
# now try to write to test2.db. the write should fail
catchsql {
INSERT INTO t2.t1 VALUES(1,2);
}
} {1 {database is locked}}
do_test attach2-2.11 {
# when the write failed in the previous test, the transaction should
# have rolled back.
#
# Update for version 3: A transaction is no longer rolled back if a
# database is found to be busy.
execsql {rollback}
db2 eval ROLLBACK
execsql {
SELECT * FROM t1
}
} {}
do_test attach2-2.12 {
catchsql {
COMMIT
}
} {1 {cannot commit - no transaction is active}}
# Ticket #574: Make sure it works using the non-callback API
#
do_test attach2-3.1 {
set DB [sqlite3_connection_pointer db]
set rc [catch {sqlite3_prepare $DB "ATTACH 'test2.db' AS t2" -1 TAIL} VM]
if {$rc} {lappend rc $VM}
sqlite3_step $VM
sqlite3_finalize $VM
set rc
} {0}
do_test attach2-3.2 {
set rc [catch {sqlite3_prepare $DB "DETACH t2" -1 TAIL} VM]
if {$rc} {lappend rc $VM}
sqlite3_step $VM
sqlite3_finalize $VM
set rc
} {0}
db close
for {set i 2} {$i<=15} {incr i} {
catch {db$i close}
}
# A procedure to verify the status of locks on a database.
#
proc lock_status {testnum db expected_result} {
# If the database was compiled with OMIT_TEMPDB set, then
# the lock_status list will not contain an entry for the temp
# db. But the test code doesn't know this, so it's easiest
# to filter it out of the $expected_result list here.
ifcapable !tempdb {
set expected_result [concat \
[lrange $expected_result 0 1] \
[lrange $expected_result 4 end] \
]
}
do_test attach2-$testnum [subst {
$db cache flush ;# The lock_status pragma should not be cached
execsql {PRAGMA lock_status} $db
}] $expected_result
}
set sqlite_os_trace 0
# Tests attach2-4.* test that read-locks work correctly with attached
# databases.
do_test attach2-4.1 {
sqlite3 db test.db
sqlite3 db2 test.db
execsql {ATTACH 'test2.db' as file2}
execsql {ATTACH 'test2.db' as file2} db2
} {}
lock_status 4.1.1 db {main unlocked temp closed file2 unlocked}
lock_status 4.1.2 db2 {main unlocked temp closed file2 unlocked}
do_test attach2-4.2 {
# Handle 'db' read-locks test.db
execsql {BEGIN}
execsql {SELECT * FROM t1}
# Lock status:
# db - shared(main)
# db2 -
} {}
lock_status 4.2.1 db {main shared temp closed file2 unlocked}
lock_status 4.2.2 db2 {main unlocked temp closed file2 unlocked}
do_test attach2-4.3 {
# The read lock held by db does not prevent db2 from reading test.db
execsql {SELECT * FROM t1} db2
} {}
lock_status 4.3.1 db {main shared temp closed file2 unlocked}
lock_status 4.3.2 db2 {main unlocked temp closed file2 unlocked}
do_test attach2-4.4 {
# db is holding a read lock on test.db, so we should not be able
# to commit a write to test.db from db2
catchsql {
INSERT INTO t1 VALUES(1, 2)
} db2
} {1 {database is locked}}
lock_status 4.4.1 db {main shared temp closed file2 unlocked}
lock_status 4.4.2 db2 {main unlocked temp closed file2 unlocked}
do_test attach2-4.5 {
# Handle 'db2' reserves file2.
execsql {BEGIN} db2
execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
# Lock status:
# db - shared(main)
# db2 - reserved(file2)
} {}
lock_status 4.5.1 db {main shared temp closed file2 unlocked}
lock_status 4.5.2 db2 {main unlocked temp closed file2 reserved}
do_test attach2-4.6.1 {
# Reads are allowed against a reserved database.
catchsql {
SELECT * FROM file2.t1;
}
# Lock status:
# db - shared(main), shared(file2)
# db2 - reserved(file2)
} {0 {}}
lock_status 4.6.1.1 db {main shared temp closed file2 shared}
lock_status 4.6.1.2 db2 {main unlocked temp closed file2 reserved}
do_test attach2-4.6.2 {
# Writes against a reserved database are not allowed.
catchsql {
UPDATE file2.t1 SET a=0;
}
} {1 {database is locked}}
lock_status 4.6.2.1 db {main shared temp closed file2 shared}
lock_status 4.6.2.2 db2 {main unlocked temp closed file2 reserved}
do_test attach2-4.7 {
# Ensure handle 'db' retains the lock on the main file after
# failing to obtain a write-lock on file2.
catchsql {
INSERT INTO t1 VALUES(1, 2)
} db2
} {0 {}}
lock_status 4.7.1 db {main shared temp closed file2 shared}
lock_status 4.7.2 db2 {main reserved temp closed file2 reserved}
do_test attach2-4.8 {
# We should still be able to read test.db from db2
execsql {SELECT * FROM t1} db2
} {1 2}
lock_status 4.8.1 db {main shared temp closed file2 shared}
lock_status 4.8.2 db2 {main reserved temp closed file2 reserved}
do_test attach2-4.9 {
# Try to upgrade the handle 'db' lock.
catchsql {
INSERT INTO t1 VALUES(1, 2)
}
} {1 {database is locked}}
lock_status 4.9.1 db {main shared temp closed file2 shared}
lock_status 4.9.2 db2 {main reserved temp closed file2 reserved}
do_test attach2-4.10 {
# We cannot commit db2 while db is holding a read-lock
catchsql {COMMIT} db2
} {1 {database is locked}}
lock_status 4.10.1 db {main shared temp closed file2 shared}
lock_status 4.10.2 db2 {main pending temp closed file2 reserved}
set sqlite_os_trace 0
do_test attach2-4.11 {
# db is able to commit.
catchsql {COMMIT}
} {0 {}}
lock_status 4.11.1 db {main unlocked temp closed file2 unlocked}
lock_status 4.11.2 db2 {main pending temp closed file2 reserved}
do_test attach2-4.12 {
# Now we can commit db2
catchsql {COMMIT} db2
} {0 {}}
lock_status 4.12.1 db {main unlocked temp closed file2 unlocked}
lock_status 4.12.2 db2 {main unlocked temp closed file2 unlocked}
do_test attach2-4.13 {
execsql {SELECT * FROM file2.t1}
} {1 2}
do_test attach2-4.14 {
execsql {INSERT INTO t1 VALUES(1, 2)}
} {}
do_test attach2-4.15 {
execsql {SELECT * FROM t1} db2
} {1 2 1 2}
db close
db2 close
file delete -force test2.db
# These tests - attach2-5.* - check that the master journal file is deleted
# correctly when a multi-file transaction is committed or rolled back.
#
# Update: It's not actually created if a rollback occurs, so that test
# doesn't really prove too much.
foreach f [glob test.db*] {file delete -force $f}
do_test attach2-5.1 {
sqlite3 db test.db
execsql {
ATTACH 'test.db2' AS aux;
}
} {}
do_test attach2-5.2 {
execsql {
BEGIN;
CREATE TABLE tbl(a, b, c);
CREATE TABLE aux.tbl(a, b, c);
COMMIT;
}
} {}
do_test attach2-5.3 {
lsort [glob test.db*]
} {test.db test.db2}
do_test attach2-5.4 {
execsql {
BEGIN;
DROP TABLE aux.tbl;
DROP TABLE tbl;
ROLLBACK;
}
} {}
do_test attach2-5.5 {
lsort [glob test.db*]
} {test.db test.db2}
# Check that a database cannot be ATTACHed or DETACHed during a transaction.
do_test attach2-6.1 {
execsql {
BEGIN;
}
} {}
do_test attach2-6.2 {
catchsql {
ATTACH 'test3.db' as aux2;
}
} {1 {cannot ATTACH database within transaction}}
do_test attach2-6.3 {
catchsql {
DETACH aux;
}
} {1 {cannot DETACH database within transaction}}
do_test attach2-6.4 {
execsql {
COMMIT;
DETACH aux;
}
} {}
db close
finish_test
+344
View File
@@ -0,0 +1,344 @@
# 2003 July 1
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the ATTACH and DETACH commands
# and schema changes to attached databases.
#
# $Id: attach3.test,v 1.17 2006/06/20 11:01:09 danielk1977 Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create tables t1 and t2 in the main database
execsql {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
}
# Create tables t1 and t2 in database file test2.db
file delete -force test2.db
file delete -force test2.db-journal
sqlite3 db2 test2.db
execsql {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
} db2
db2 close
# Create a table in the auxilary database.
do_test attach3-1.1 {
execsql {
ATTACH 'test2.db' AS aux;
}
} {}
do_test attach3-1.2 {
execsql {
CREATE TABLE aux.t3(e, f);
}
} {}
do_test attach3-1.3 {
execsql {
SELECT * FROM sqlite_master WHERE name = 't3';
}
} {}
do_test attach3-1.4 {
execsql {
SELECT * FROM aux.sqlite_master WHERE name = 't3';
}
} "table t3 t3 [expr $AUTOVACUUM?5:4] {CREATE TABLE t3(e, f)}"
do_test attach3-1.5 {
execsql {
INSERT INTO t3 VALUES(1, 2);
SELECT * FROM t3;
}
} {1 2}
# Create an index on the auxilary database table.
do_test attach3-2.1 {
execsql {
CREATE INDEX aux.i1 on t3(e);
}
} {}
do_test attach3-2.2 {
execsql {
SELECT * FROM sqlite_master WHERE name = 'i1';
}
} {}
do_test attach3-2.3 {
execsql {
SELECT * FROM aux.sqlite_master WHERE name = 'i1';
}
} "index i1 t3 [expr $AUTOVACUUM?6:5] {CREATE INDEX i1 on t3(e)}"
# Drop the index on the aux database table.
do_test attach3-3.1 {
execsql {
DROP INDEX aux.i1;
SELECT * FROM aux.sqlite_master WHERE name = 'i1';
}
} {}
do_test attach3-3.2 {
execsql {
CREATE INDEX aux.i1 on t3(e);
SELECT * FROM aux.sqlite_master WHERE name = 'i1';
}
} "index i1 t3 [expr $AUTOVACUUM?6:5] {CREATE INDEX i1 on t3(e)}"
do_test attach3-3.3 {
execsql {
DROP INDEX i1;
SELECT * FROM aux.sqlite_master WHERE name = 'i1';
}
} {}
# Drop tables t1 and t2 in the auxilary database.
do_test attach3-4.1 {
execsql {
DROP TABLE aux.t1;
SELECT name FROM aux.sqlite_master;
}
} {t2 t3}
do_test attach3-4.2 {
# This will drop main.t2
execsql {
DROP TABLE t2;
SELECT name FROM aux.sqlite_master;
}
} {t2 t3}
do_test attach3-4.3 {
execsql {
DROP TABLE t2;
SELECT name FROM aux.sqlite_master;
}
} {t3}
# Create a view in the auxilary database.
ifcapable view {
do_test attach3-5.1 {
execsql {
CREATE VIEW aux.v1 AS SELECT * FROM t3;
}
} {}
do_test attach3-5.2 {
execsql {
SELECT * FROM aux.sqlite_master WHERE name = 'v1';
}
} {view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t3}}
do_test attach3-5.3 {
execsql {
INSERT INTO aux.t3 VALUES('hello', 'world');
SELECT * FROM v1;
}
} {1 2 hello world}
# Drop the view
do_test attach3-6.1 {
execsql {
DROP VIEW aux.v1;
}
} {}
do_test attach3-6.2 {
execsql {
SELECT * FROM aux.sqlite_master WHERE name = 'v1';
}
} {}
} ;# ifcapable view
ifcapable {trigger} {
# Create a trigger in the auxilary database.
do_test attach3-7.1 {
execsql {
CREATE TRIGGER aux.tr1 AFTER INSERT ON t3 BEGIN
INSERT INTO t3 VALUES(new.e*2, new.f*2);
END;
}
} {}
do_test attach3-7.2 {
execsql {
DELETE FROM t3;
INSERT INTO t3 VALUES(10, 20);
SELECT * FROM t3;
}
} {10 20 20 40}
do_test attach3-5.3 {
execsql {
SELECT * FROM aux.sqlite_master WHERE name = 'tr1';
}
} {trigger tr1 t3 0 {CREATE TRIGGER tr1 AFTER INSERT ON t3 BEGIN
INSERT INTO t3 VALUES(new.e*2, new.f*2);
END}}
# Drop the trigger
do_test attach3-8.1 {
execsql {
DROP TRIGGER aux.tr1;
}
} {}
do_test attach3-8.2 {
execsql {
SELECT * FROM aux.sqlite_master WHERE name = 'tr1';
}
} {}
ifcapable tempdb {
# Try to trick SQLite into dropping the wrong temp trigger.
do_test attach3-9.0 {
execsql {
CREATE TABLE main.t4(a, b, c);
CREATE TABLE aux.t4(a, b, c);
CREATE TEMP TRIGGER tst_trigger BEFORE INSERT ON aux.t4 BEGIN
SELECT 'hello world';
END;
SELECT count(*) FROM sqlite_temp_master;
}
} {1}
do_test attach3-9.1 {
execsql {
DROP TABLE main.t4;
SELECT count(*) FROM sqlite_temp_master;
}
} {1}
do_test attach3-9.2 {
execsql {
DROP TABLE aux.t4;
SELECT count(*) FROM sqlite_temp_master;
}
} {0}
}
} ;# endif trigger
# Make sure the aux.sqlite_master table is read-only
do_test attach3-10.0 {
catchsql {
INSERT INTO aux.sqlite_master VALUES(1, 2, 3, 4, 5);
}
} {1 {table sqlite_master may not be modified}}
# Failure to attach leaves us in a workable state.
# Ticket #811
#
do_test attach3-11.0 {
catchsql {
ATTACH DATABASE '/nodir/nofile.x' AS notadb;
}
} {1 {unable to open database: /nodir/nofile.x}}
do_test attach3-11.1 {
catchsql {
ATTACH DATABASE ':memory:' AS notadb;
}
} {0 {}}
do_test attach3-11.2 {
catchsql {
DETACH DATABASE notadb;
}
} {0 {}}
# Return a list of attached databases
#
proc db_list {} {
set x [execsql {
PRAGMA database_list;
}]
set y {}
foreach {n id file} $x {lappend y $id}
return $y
}
ifcapable schema_pragmas&&tempdb {
ifcapable !trigger {
execsql {create temp table dummy(dummy)}
}
# Ticket #1825
#
do_test attach3-12.1 {
db_list
} {main temp aux}
do_test attach3-12.2 {
execsql {
ATTACH DATABASE ? AS ?
}
db_list
} {main temp aux {}}
do_test attach3-12.3 {
execsql {
DETACH aux
}
db_list
} {main temp {}}
do_test attach3-12.4 {
execsql {
DETACH ?
}
db_list
} {main temp}
do_test attach3-12.5 {
execsql {
ATTACH DATABASE '' AS ''
}
db_list
} {main temp {}}
do_test attach3-12.6 {
execsql {
DETACH ''
}
db_list
} {main temp}
do_test attach3-12.7 {
execsql {
ATTACH DATABASE '' AS ?
}
db_list
} {main temp {}}
do_test attach3-12.8 {
execsql {
DETACH ''
}
db_list
} {main temp}
do_test attach3-12.9 {
execsql {
ATTACH DATABASE '' AS NULL
}
db_list
} {main temp {}}
do_test attach3-12.10 {
execsql {
DETACH ?
}
db_list
} {main temp}
do_test attach3-12.11 {
catchsql {
DETACH NULL
}
} {1 {no such database: }}
do_test attach3-12.12 {
catchsql {
ATTACH null AS null;
ATTACH '' AS '';
}
} {1 {database is already in use}}
do_test attach3-12.13 {
db_list
} {main temp {}}
do_test attach3-12.14 {
execsql {
DETACH '';
}
db_list
} {main temp}
} ;# ifcapable pragma
finish_test
+127
View File
@@ -0,0 +1,127 @@
# 2005 September 19
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the ATTACH statement and
# specifically out-of-memory conditions within that command.
#
# $Id: attachmalloc.test,v 1.3 2006/09/04 18:54:14 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if memory debugging is turned on.
#
if {[info command sqlite_malloc_stat]==""} {
puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG=1"
finish_test
return
}
# Usage: do_malloc_test <test name> <options...>
#
# The first argument, <test number>, is an integer used to name the
# tests executed by this proc. Options are as follows:
#
# -tclprep TCL script to run to prepare test.
# -sqlprep SQL script to run to prepare test.
# -tclbody TCL script to run with malloc failure simulation.
# -sqlbody TCL script to run with malloc failure simulation.
# -cleanup TCL script to run after the test.
#
# This command runs a series of tests to verify SQLite's ability
# to handle an out-of-memory condition gracefully. It is assumed
# that if this condition occurs a malloc() call will return a
# NULL pointer. Linux, for example, doesn't do that by default. See
# the "BUGS" section of malloc(3).
#
# Each iteration of a loop, the TCL commands in any argument passed
# to the -tclbody switch, followed by the SQL commands in any argument
# passed to the -sqlbody switch are executed. Each iteration the
# Nth call to sqliteMalloc() is made to fail, where N is increased
# each time the loop runs starting from 1. When all commands execute
# successfully, the loop ends.
#
proc do_malloc_test {tn args} {
array set ::mallocopts $args
set ::go 1
for {set ::n 1} {$::go} {incr ::n} {
do_test $tn.$::n {
sqlite_malloc_fail 0
catch {db close}
catch {file delete -force test.db}
catch {file delete -force test.db-journal}
catch {file delete -force test2.db}
catch {file delete -force test2.db-journal}
set ::DB [sqlite3 db test.db]
if {[info exists ::mallocopts(-tclprep)]} {
eval $::mallocopts(-tclprep)
}
if {[info exists ::mallocopts(-sqlprep)]} {
execsql $::mallocopts(-sqlprep)
}
sqlite_malloc_fail $::n
set ::mallocbody {}
if {[info exists ::mallocopts(-tclbody)]} {
append ::mallocbody "$::mallocopts(-tclbody)\n"
}
if {[info exists ::mallocopts(-sqlbody)]} {
append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
}
set v [catch $::mallocbody msg]
set leftover [lindex [sqlite_malloc_stat] 2]
if {$leftover>0} {
if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
set ::go 0
set v {1 1}
} else {
set v2 [expr {$msg=="" || $msg=="out of memory"}]
if {!$v2} {puts "\nError message returned: $msg"}
lappend v $v2
}
} {1 1}
sqlite_malloc_fail 0
if {[info exists ::mallocopts(-cleanup)]} {
catch $::mallocopts(-cleanup)
}
}
unset ::mallocopts
}
do_malloc_test attachmalloc-1 -tclprep {
db close
for {set i 2} {$i<=4} {incr i} {
file delete -force test$i.db
file delete -force test$i.db-journal
}
} -tclbody {
if {[catch {sqlite3 db test.db}]} {
error "out of memory"
}
} -sqlbody {
ATTACH 'test2.db' AS two;
CREATE TABLE two.t1(x);
ATTACH 'test3.db' AS three;
CREATE TABLE three.t1(x);
ATTACH 'test4.db' AS four;
CREATE TABLE four.t1(x);
}
finish_test
File diff suppressed because it is too large Load Diff
+75
View File
@@ -0,0 +1,75 @@
# 2006 Aug 24
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the sqlite3_set_authorizer() API
# and related functionality.
#
# $Id: auth2.test,v 1.1 2006/08/24 14:59:46 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# disable this test if the SQLITE_OMIT_AUTHORIZATION macro is
# defined during compilation.
if {[catch {db auth {}} msg]} {
finish_test
return
}
do_test auth2-1.1 {
execsql {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(1,2,3);
}
set ::flist {}
proc auth {code arg1 arg2 arg3 arg4} {
if {$code=="SQLITE_FUNCTION"} {
lappend ::flist $arg2
if {$arg2=="max"} {
return SQLITE_DENY
} elseif {$arg2=="min"} {
return SQLITE_IGNORE
} else {
return SQLITE_OK
}
}
return SQLITE_OK
}
db authorizer ::auth
catchsql {SELECT max(a,b,c) FROM t1}
} {1 {not authorized to use function: max}}
do_test auth2-1.2 {
set ::flist
} max
do_test auth2-1.3 {
set ::flist {}
catchsql {SELECT min(a,b,c) FROM t1}
} {0 {{}}}
do_test auth2-1.4 {
set ::flist
} min
do_test auth2-1.5 {
set ::flist {}
catchsql {SELECT coalesce(min(a,b,c),999) FROM t1}
} {0 999}
do_test auth2-1.6 {
set ::flist
} {coalesce min}
do_test auth2-1.7 {
set ::flist {}
catchsql {SELECT coalesce(a,b,c) FROM t1}
} {0 1}
do_test auth2-1.8 {
set ::flist
} coalesce
finish_test
+536
View File
@@ -0,0 +1,536 @@
# 2004 November 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.
#
#*************************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is testing the AUTOINCREMENT features.
#
# $Id: autoinc.test,v 1.9 2006/01/03 00:33:50 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If the library is not compiled with autoincrement support then
# skip all tests in this file.
#
ifcapable {!autoinc} {
finish_test
return
}
# The database is initially empty.
#
do_test autoinc-1.1 {
execsql {
SELECT name FROM sqlite_master WHERE type='table';
}
} {}
# Add a table with the AUTOINCREMENT feature. Verify that the
# SQLITE_SEQUENCE table gets created.
#
do_test autoinc-1.2 {
execsql {
CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
SELECT name FROM sqlite_master WHERE type='table';
}
} {t1 sqlite_sequence}
# The SQLITE_SEQUENCE table is initially empty
#
do_test autoinc-1.3 {
execsql {
SELECT * FROM sqlite_sequence;
}
} {}
# Close and reopen the database. Verify that everything is still there.
#
do_test autoinc-1.4 {
db close
sqlite3 db test.db
execsql {
SELECT * FROM sqlite_sequence;
}
} {}
# We are not allowed to drop the sqlite_sequence table.
#
do_test autoinc-1.5 {
catchsql {DROP TABLE sqlite_sequence}
} {1 {table sqlite_sequence may not be dropped}}
do_test autoinc-1.6 {
execsql {SELECT name FROM sqlite_master WHERE type='table'}
} {t1 sqlite_sequence}
# Insert an entries into the t1 table and make sure the largest key
# is always recorded in the sqlite_sequence table.
#
do_test autoinc-2.1 {
execsql {
SELECT * FROM sqlite_sequence
}
} {}
do_test autoinc-2.2 {
execsql {
INSERT INTO t1 VALUES(12,34);
SELECT * FROM sqlite_sequence;
}
} {t1 12}
do_test autoinc-2.3 {
execsql {
INSERT INTO t1 VALUES(1,23);
SELECT * FROM sqlite_sequence;
}
} {t1 12}
do_test autoinc-2.4 {
execsql {
INSERT INTO t1 VALUES(123,456);
SELECT * FROM sqlite_sequence;
}
} {t1 123}
do_test autoinc-2.5 {
execsql {
INSERT INTO t1 VALUES(NULL,567);
SELECT * FROM sqlite_sequence;
}
} {t1 124}
do_test autoinc-2.6 {
execsql {
DELETE FROM t1 WHERE y=567;
SELECT * FROM sqlite_sequence;
}
} {t1 124}
do_test autoinc-2.7 {
execsql {
INSERT INTO t1 VALUES(NULL,567);
SELECT * FROM sqlite_sequence;
}
} {t1 125}
do_test autoinc-2.8 {
execsql {
DELETE FROM t1;
SELECT * FROM sqlite_sequence;
}
} {t1 125}
do_test autoinc-2.9 {
execsql {
INSERT INTO t1 VALUES(12,34);
SELECT * FROM sqlite_sequence;
}
} {t1 125}
do_test autoinc-2.10 {
execsql {
INSERT INTO t1 VALUES(125,456);
SELECT * FROM sqlite_sequence;
}
} {t1 125}
do_test autoinc-2.11 {
execsql {
INSERT INTO t1 VALUES(-1234567,-1);
SELECT * FROM sqlite_sequence;
}
} {t1 125}
do_test autoinc-2.12 {
execsql {
INSERT INTO t1 VALUES(234,5678);
SELECT * FROM sqlite_sequence;
}
} {t1 234}
do_test autoinc-2.13 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES(NULL,1);
SELECT * FROM sqlite_sequence;
}
} {t1 235}
do_test autoinc-2.14 {
execsql {
SELECT * FROM t1;
}
} {235 1}
# Manually change the autoincrement values in sqlite_sequence.
#
do_test autoinc-2.20 {
execsql {
UPDATE sqlite_sequence SET seq=1234 WHERE name='t1';
INSERT INTO t1 VALUES(NULL,2);
SELECT * FROM t1;
}
} {235 1 1235 2}
do_test autoinc-2.21 {
execsql {
SELECT * FROM sqlite_sequence;
}
} {t1 1235}
do_test autoinc-2.22 {
execsql {
UPDATE sqlite_sequence SET seq=NULL WHERE name='t1';
INSERT INTO t1 VALUES(NULL,3);
SELECT * FROM t1;
}
} {235 1 1235 2 1236 3}
do_test autoinc-2.23 {
execsql {
SELECT * FROM sqlite_sequence;
}
} {t1 1236}
do_test autoinc-2.24 {
execsql {
UPDATE sqlite_sequence SET seq='a-string' WHERE name='t1';
INSERT INTO t1 VALUES(NULL,4);
SELECT * FROM t1;
}
} {235 1 1235 2 1236 3 1237 4}
do_test autoinc-2.25 {
execsql {
SELECT * FROM sqlite_sequence;
}
} {t1 1237}
do_test autoinc-2.26 {
execsql {
DELETE FROM sqlite_sequence WHERE name='t1';
INSERT INTO t1 VALUES(NULL,5);
SELECT * FROM t1;
}
} {235 1 1235 2 1236 3 1237 4 1238 5}
do_test autoinc-2.27 {
execsql {
SELECT * FROM sqlite_sequence;
}
} {t1 1238}
do_test autoinc-2.28 {
execsql {
UPDATE sqlite_sequence SET seq='12345678901234567890'
WHERE name='t1';
INSERT INTO t1 VALUES(NULL,6);
SELECT * FROM t1;
}
} {235 1 1235 2 1236 3 1237 4 1238 5 1239 6}
do_test autoinc-2.29 {
execsql {
SELECT * FROM sqlite_sequence;
}
} {t1 1239}
# Test multi-row inserts
#
do_test autoinc-2.50 {
execsql {
DELETE FROM t1 WHERE y>=3;
INSERT INTO t1 SELECT NULL, y+2 FROM t1;
SELECT * FROM t1;
}
} {235 1 1235 2 1240 3 1241 4}
do_test autoinc-2.51 {
execsql {
SELECT * FROM sqlite_sequence
}
} {t1 1241}
ifcapable tempdb {
do_test autoinc-2.52 {
execsql {
CREATE TEMP TABLE t2 AS SELECT y FROM t1;
INSERT INTO t1 SELECT NULL, y+4 FROM t2;
SELECT * FROM t1;
}
} {235 1 1235 2 1240 3 1241 4 1242 5 1243 6 1244 7 1245 8}
do_test autoinc-2.53 {
execsql {
SELECT * FROM sqlite_sequence
}
} {t1 1245}
do_test autoinc-2.54 {
execsql {
DELETE FROM t1;
INSERT INTO t1 SELECT NULL, y FROM t2;
SELECT * FROM t1;
}
} {1246 1 1247 2 1248 3 1249 4}
do_test autoinc-2.55 {
execsql {
SELECT * FROM sqlite_sequence
}
} {t1 1249}
}
# Create multiple AUTOINCREMENT tables. Make sure all sequences are
# tracked separately and do not interfere with one another.
#
do_test autoinc-2.70 {
catchsql {
DROP TABLE t2;
}
execsql {
CREATE TABLE t2(d, e INTEGER PRIMARY KEY AUTOINCREMENT, f);
INSERT INTO t2(d) VALUES(1);
SELECT * FROM sqlite_sequence;
}
} [ifcapable tempdb {list t1 1249 t2 1} else {list t1 1241 t2 1}]
do_test autoinc-2.71 {
execsql {
INSERT INTO t2(d) VALUES(2);
SELECT * FROM sqlite_sequence;
}
} [ifcapable tempdb {list t1 1249 t2 2} else {list t1 1241 t2 2}]
do_test autoinc-2.72 {
execsql {
INSERT INTO t1(x) VALUES(10000);
SELECT * FROM sqlite_sequence;
}
} {t1 10000 t2 2}
do_test autoinc-2.73 {
execsql {
CREATE TABLE t3(g INTEGER PRIMARY KEY AUTOINCREMENT, h);
INSERT INTO t3(h) VALUES(1);
SELECT * FROM sqlite_sequence;
}
} {t1 10000 t2 2 t3 1}
do_test autoinc-2.74 {
execsql {
INSERT INTO t2(d,e) VALUES(3,100);
SELECT * FROM sqlite_sequence;
}
} {t1 10000 t2 100 t3 1}
# When a table with an AUTOINCREMENT is deleted, the corresponding entry
# in the SQLITE_SEQUENCE table should also be deleted. But the SQLITE_SEQUENCE
# table itself should remain behind.
#
do_test autoinc-3.1 {
execsql {SELECT name FROM sqlite_sequence}
} {t1 t2 t3}
do_test autoinc-3.2 {
execsql {
DROP TABLE t1;
SELECT name FROM sqlite_sequence;
}
} {t2 t3}
do_test autoinc-3.3 {
execsql {
DROP TABLE t3;
SELECT name FROM sqlite_sequence;
}
} {t2}
do_test autoinc-3.4 {
execsql {
DROP TABLE t2;
SELECT name FROM sqlite_sequence;
}
} {}
# AUTOINCREMENT on TEMP tables.
#
ifcapable tempdb {
do_test autoinc-4.1 {
execsql {
SELECT 1, name FROM sqlite_master WHERE type='table';
SELECT 2, name FROM sqlite_temp_master WHERE type='table';
}
} {1 sqlite_sequence}
do_test autoinc-4.2 {
execsql {
CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
CREATE TEMP TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
SELECT 1, name FROM sqlite_master WHERE type='table';
SELECT 2, name FROM sqlite_temp_master WHERE type='table';
}
} {1 sqlite_sequence 1 t1 2 t3 2 sqlite_sequence}
do_test autoinc-4.3 {
execsql {
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {}
do_test autoinc-4.4 {
execsql {
INSERT INTO t1 VALUES(10,1);
INSERT INTO t3 VALUES(20,2);
INSERT INTO t1 VALUES(NULL,3);
INSERT INTO t3 VALUES(NULL,4);
}
} {}
ifcapable compound {
do_test autoinc-4.4.1 {
execsql {
SELECT * FROM t1 UNION ALL SELECT * FROM t3;
}
} {10 1 11 3 20 2 21 4}
} ;# ifcapable compound
do_test autoinc-4.5 {
execsql {
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {1 t1 11 2 t3 21}
do_test autoinc-4.6 {
execsql {
INSERT INTO t1 SELECT * FROM t3;
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {1 t1 21 2 t3 21}
do_test autoinc-4.7 {
execsql {
INSERT INTO t3 SELECT x+100, y FROM t1;
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {1 t1 21 2 t3 121}
do_test autoinc-4.8 {
execsql {
DROP TABLE t3;
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {1 t1 21}
do_test autoinc-4.9 {
execsql {
CREATE TEMP TABLE t2(p INTEGER PRIMARY KEY AUTOINCREMENT, q);
INSERT INTO t2 SELECT * FROM t1;
DROP TABLE t1;
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {2 t2 21}
do_test autoinc-4.10 {
execsql {
DROP TABLE t2;
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
}
} {}
}
# Make sure AUTOINCREMENT works on ATTACH-ed tables.
#
ifcapable tempdb {
do_test autoinc-5.1 {
file delete -force test2.db
file delete -force test2.db-journal
sqlite3 db2 test2.db
execsql {
CREATE TABLE t4(m INTEGER PRIMARY KEY AUTOINCREMENT, n);
CREATE TABLE t5(o, p INTEGER PRIMARY KEY AUTOINCREMENT);
} db2;
execsql {
ATTACH 'test2.db' as aux;
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
SELECT 3, * FROM aux.sqlite_sequence;
}
} {}
do_test autoinc-5.2 {
execsql {
INSERT INTO t4 VALUES(NULL,1);
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
SELECT 3, * FROM aux.sqlite_sequence;
}
} {3 t4 1}
do_test autoinc-5.3 {
execsql {
INSERT INTO t5 VALUES(100,200);
SELECT * FROM sqlite_sequence
} db2
} {t4 1 t5 200}
do_test autoinc-5.4 {
execsql {
SELECT 1, * FROM main.sqlite_sequence;
SELECT 2, * FROM temp.sqlite_sequence;
SELECT 3, * FROM aux.sqlite_sequence;
}
} {3 t4 1 3 t5 200}
}
# Requirement REQ00310: Make sure an insert fails if the sequence is
# already at its maximum value.
#
ifcapable {rowid32} {
do_test autoinc-6.1 {
execsql {
CREATE TABLE t6(v INTEGER PRIMARY KEY AUTOINCREMENT, w);
INSERT INTO t6 VALUES(2147483647,1);
SELECT seq FROM main.sqlite_sequence WHERE name='t6';
}
} 2147483647
}
ifcapable {!rowid32} {
do_test autoinc-6.1 {
execsql {
CREATE TABLE t6(v INTEGER PRIMARY KEY AUTOINCREMENT, w);
INSERT INTO t6 VALUES(9223372036854775807,1);
SELECT seq FROM main.sqlite_sequence WHERE name='t6';
}
} 9223372036854775807
}
do_test autoinc-6.2 {
catchsql {
INSERT INTO t6 VALUES(NULL,1);
}
} {1 {database or disk is full}}
# Allow the AUTOINCREMENT keyword inside the parentheses
# on a separate PRIMARY KEY designation.
#
do_test autoinc-7.1 {
execsql {
CREATE TABLE t7(x INTEGER, y REAL, PRIMARY KEY(x AUTOINCREMENT));
INSERT INTO t7(y) VALUES(123);
INSERT INTO t7(y) VALUES(234);
DELETE FROM t7;
INSERT INTO t7(y) VALUES(345);
SELECT * FROM t7;
}
} {3 345.0}
# Test that if the AUTOINCREMENT is applied to a non integer primary key
# the error message is sensible.
do_test autoinc-7.2 {
catchsql {
CREATE TABLE t8(x TEXT PRIMARY KEY AUTOINCREMENT);
}
} {1 {AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY}}
# Ticket #1283. Make sure that preparing but never running a statement
# that creates the sqlite_sequence table does not mess up the database.
#
do_test autoinc-8.1 {
catch {db2 close}
catch {db close}
file delete -force test.db
sqlite3 db test.db
set DB [sqlite3_connection_pointer db]
set STMT [sqlite3_prepare $DB {
CREATE TABLE t1(
x INTEGER PRIMARY KEY AUTOINCREMENT
)
} -1 TAIL]
sqlite3_finalize $STMT
set STMT [sqlite3_prepare $DB {
CREATE TABLE t1(
x INTEGER PRIMARY KEY AUTOINCREMENT
)
} -1 TAIL]
sqlite3_step $STMT
sqlite3_finalize $STMT
execsql {
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
}
} {1}
finish_test
+582
View File
@@ -0,0 +1,582 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the SELECT statement.
#
# $Id: autovacuum.test,v 1.24 2006/08/12 12:33:15 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum || !pragma} {
finish_test
return
}
# Return a string $len characters long. The returned string is $char repeated
# over and over. For example, [make_str abc 8] returns "abcabcab".
proc make_str {char len} {
set str [string repeat $char. $len]
return [string range $str 0 [expr $len-1]]
}
# Return the number of pages in the file test.db by looking at the file system.
proc file_pages {} {
return [expr [file size test.db] / 1024]
}
#-------------------------------------------------------------------------
# Test cases autovacuum-1.* work as follows:
#
# 1. A table with a single indexed field is created.
# 2. Approximately 20 rows are inserted into the table. Each row is long
# enough such that it uses at least 2 overflow pages for both the table
# and index entry.
# 3. The rows are deleted in a psuedo-random order. Sometimes only one row
# is deleted per transaction, sometimes more than one.
# 4. After each transaction the table data is checked to ensure it is correct
# and a "PRAGMA integrity_check" is executed.
# 5. Once all the rows are deleted the file is checked to make sure it
# consists of exactly 4 pages.
#
# Steps 2-5 are repeated for a few different psuedo-random delete patterns
# (defined by the $delete_orders list).
set delete_orders [list]
lappend delete_orders {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20}
lappend delete_orders {20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1}
lappend delete_orders {8 18 2 4 14 11 13 3 10 7 9 5 12 17 19 15 20 6 16 1}
lappend delete_orders {10 3 11 17 19 20 7 4 13 6 1 14 16 12 9 18 8 15 5 2}
lappend delete_orders {{1 2 3 4 5 6 7 8 9 10} {11 12 13 14 15 16 17 18 19 20}}
lappend delete_orders {{19 8 17 15} {16 11 9 14} {18 5 3 1} {13 20 7 2} {6 12}}
# The length of each table entry.
# set ENTRY_LEN 3500
set ENTRY_LEN 3500
do_test autovacuum-1.1 {
execsql {
PRAGMA auto_vacuum = 1;
CREATE TABLE av1(a);
CREATE INDEX av1_idx ON av1(a);
}
} {}
set tn 0
foreach delete_order $delete_orders {
incr tn
# Set up the table.
set ::tbl_data [list]
foreach i [lsort -integer [eval concat $delete_order]] {
execsql "INSERT INTO av1 (oid, a) VALUES($i, '[make_str $i $ENTRY_LEN]')"
lappend ::tbl_data [make_str $i $ENTRY_LEN]
}
# Make sure the integrity check passes with the initial data.
ifcapable {integrityck} {
do_test autovacuum-1.$tn.1 {
execsql {
pragma integrity_check
}
} {ok}
}
foreach delete $delete_order {
# Delete one set of rows from the table.
do_test autovacuum-1.$tn.($delete).1 {
execsql "
DELETE FROM av1 WHERE oid = [join $delete " OR oid = "]
"
} {}
# Do the integrity check.
ifcapable {integrityck} {
do_test autovacuum-1.$tn.($delete).2 {
execsql {
pragma integrity_check
}
} {ok}
}
# Ensure the data remaining in the table is what was expected.
foreach d $delete {
set idx [lsearch $::tbl_data [make_str $d $ENTRY_LEN]]
set ::tbl_data [lreplace $::tbl_data $idx $idx]
}
do_test autovacuum-1.$tn.($delete).3 {
execsql {
select a from av1
}
} $::tbl_data
}
# All rows have been deleted. Ensure the file has shrunk to 4 pages.
do_test autovacuum-1.$tn.3 {
file_pages
} {4}
}
#---------------------------------------------------------------------------
# Tests cases autovacuum-2.* test that root pages are allocated
# and deallocated correctly at the start of the file. Operation is roughly as
# follows:
#
# autovacuum-2.1.*: Drop the tables that currently exist in the database.
# autovacuum-2.2.*: Create some tables. Ensure that data pages can be
# moved correctly to make space for new root-pages.
# autovacuum-2.3.*: Drop one of the tables just created (not the last one),
# and check that one of the other tables is moved to
# the free root-page location.
# autovacuum-2.4.*: Check that a table can be created correctly when the
# root-page it requires is on the free-list.
# autovacuum-2.5.*: Check that a table with indices can be dropped. This
# is slightly tricky because dropping one of the
# indices/table btrees could move the root-page of another.
# The code-generation layer of SQLite overcomes this problem
# by dropping the btrees in descending order of root-pages.
# This test ensures that this actually happens.
#
do_test autovacuum-2.1.1 {
execsql {
DROP TABLE av1;
}
} {}
do_test autovacuum-2.1.2 {
file_pages
} {1}
# Create a table and put some data in it.
do_test autovacuum-2.2.1 {
execsql {
CREATE TABLE av1(x);
SELECT rootpage FROM sqlite_master ORDER BY rootpage;
}
} {3}
do_test autovacuum-2.2.2 {
execsql "
INSERT INTO av1 VALUES('[make_str abc 3000]');
INSERT INTO av1 VALUES('[make_str def 3000]');
INSERT INTO av1 VALUES('[make_str ghi 3000]');
INSERT INTO av1 VALUES('[make_str jkl 3000]');
"
set ::av1_data [db eval {select * from av1}]
file_pages
} {15}
# Create another table. Check it is located immediately after the first.
# This test case moves the second page in an over-flow chain.
do_test autovacuum-2.2.3 {
execsql {
CREATE TABLE av2(x);
SELECT rootpage FROM sqlite_master ORDER BY rootpage;
}
} {3 4}
do_test autovacuum-2.2.4 {
file_pages
} {16}
# Create another table. Check it is located immediately after the second.
# This test case moves the first page in an over-flow chain.
do_test autovacuum-2.2.5 {
execsql {
CREATE TABLE av3(x);
SELECT rootpage FROM sqlite_master ORDER BY rootpage;
}
} {3 4 5}
do_test autovacuum-2.2.6 {
file_pages
} {17}
# Create another table. Check it is located immediately after the second.
# This test case moves a btree leaf page.
do_test autovacuum-2.2.7 {
execsql {
CREATE TABLE av4(x);
SELECT rootpage FROM sqlite_master ORDER BY rootpage;
}
} {3 4 5 6}
do_test autovacuum-2.2.8 {
file_pages
} {18}
do_test autovacuum-2.2.9 {
execsql {
select * from av1
}
} $av1_data
do_test autovacuum-2.3.1 {
execsql {
INSERT INTO av2 SELECT 'av1' || x FROM av1;
INSERT INTO av3 SELECT 'av2' || x FROM av1;
INSERT INTO av4 SELECT 'av3' || x FROM av1;
}
set ::av2_data [execsql {select x from av2}]
set ::av3_data [execsql {select x from av3}]
set ::av4_data [execsql {select x from av4}]
file_pages
} {54}
do_test autovacuum-2.3.2 {
execsql {
DROP TABLE av2;
SELECT rootpage FROM sqlite_master ORDER BY rootpage;
}
} {3 4 5}
do_test autovacuum-2.3.3 {
file_pages
} {41}
do_test autovacuum-2.3.4 {
execsql {
SELECT x FROM av3;
}
} $::av3_data
do_test autovacuum-2.3.5 {
execsql {
SELECT x FROM av4;
}
} $::av4_data
# Drop all the tables in the file. This puts all pages except the first 2
# (the sqlite_master root-page and the first pointer map page) on the
# free-list.
do_test autovacuum-2.4.1 {
execsql {
DROP TABLE av1;
DROP TABLE av3;
BEGIN;
DROP TABLE av4;
}
file_pages
} {15}
do_test autovacuum-2.4.2 {
for {set i 3} {$i<=10} {incr i} {
execsql "CREATE TABLE av$i (x)"
}
file_pages
} {15}
do_test autovacuum-2.4.3 {
execsql {
SELECT rootpage FROM sqlite_master ORDER by rootpage
}
} {3 4 5 6 7 8 9 10}
# Right now there are 5 free pages in the database. Consume and then free
# a 520 pages. Then create 520 tables. This ensures that at least some of the
# desired root-pages reside on the second free-list trunk page, and that the
# trunk itself is required at some point.
do_test autovacuum-2.4.4 {
execsql "
INSERT INTO av3 VALUES ('[make_str abcde [expr 1020*520 + 500]]');
DELETE FROM av3;
"
} {}
set root_page_list [list]
set pending_byte_page [expr ($::sqlite_pending_byte / 1024) + 1]
for {set i 3} {$i<=532} {incr i} {
# 207 and 412 are pointer-map pages.
if { $i!=207 && $i!=412 && $i != $pending_byte_page} {
lappend root_page_list $i
}
}
if {$i >= $pending_byte_page} {
lappend root_page_list $i
}
do_test autovacuum-2.4.5 {
for {set i 11} {$i<=530} {incr i} {
execsql "CREATE TABLE av$i (x)"
}
execsql {
SELECT rootpage FROM sqlite_master ORDER by rootpage
}
} $root_page_list
# Just for fun, delete all those tables and see if the database is 1 page.
do_test autovacuum-2.4.6 {
execsql COMMIT;
file_pages
} [expr 561 + (($i >= $pending_byte_page)?1:0)]
integrity_check autovacuum-2.4.6
do_test autovacuum-2.4.7 {
execsql BEGIN
for {set i 3} {$i<=530} {incr i} {
execsql "DROP TABLE av$i"
}
execsql COMMIT
file_pages
} 1
# Create some tables with indices to drop.
do_test autovacuum-2.5.1 {
execsql {
CREATE TABLE av1(a PRIMARY KEY, b, c);
INSERT INTO av1 VALUES('av1 a', 'av1 b', 'av1 c');
CREATE TABLE av2(a PRIMARY KEY, b, c);
CREATE INDEX av2_i1 ON av2(b);
CREATE INDEX av2_i2 ON av2(c);
INSERT INTO av2 VALUES('av2 a', 'av2 b', 'av2 c');
CREATE TABLE av3(a PRIMARY KEY, b, c);
CREATE INDEX av3_i1 ON av3(b);
INSERT INTO av3 VALUES('av3 a', 'av3 b', 'av3 c');
CREATE TABLE av4(a, b, c);
CREATE INDEX av4_i1 ON av4(a);
CREATE INDEX av4_i2 ON av4(b);
CREATE INDEX av4_i3 ON av4(c);
CREATE INDEX av4_i4 ON av4(a, b, c);
INSERT INTO av4 VALUES('av4 a', 'av4 b', 'av4 c');
}
} {}
do_test autovacuum-2.5.2 {
execsql {
SELECT name, rootpage FROM sqlite_master;
}
} [list av1 3 sqlite_autoindex_av1_1 4 \
av2 5 sqlite_autoindex_av2_1 6 av2_i1 7 av2_i2 8 \
av3 9 sqlite_autoindex_av3_1 10 av3_i1 11 \
av4 12 av4_i1 13 av4_i2 14 av4_i3 15 av4_i4 16 \
]
# The following 4 tests are SELECT queries that use the indices created.
# If the root-pages in the internal schema are not updated correctly when
# a table or indice is moved, these queries will fail. They are repeated
# after each table is dropped (i.e. as test cases 2.5.*.[1..4]).
do_test autovacuum-2.5.2.1 {
execsql {
SELECT * FROM av1 WHERE a = 'av1 a';
}
} {{av1 a} {av1 b} {av1 c}}
do_test autovacuum-2.5.2.2 {
execsql {
SELECT * FROM av2 WHERE a = 'av2 a' AND b = 'av2 b' AND c = 'av2 c'
}
} {{av2 a} {av2 b} {av2 c}}
do_test autovacuum-2.5.2.3 {
execsql {
SELECT * FROM av3 WHERE a = 'av3 a' AND b = 'av3 b';
}
} {{av3 a} {av3 b} {av3 c}}
do_test autovacuum-2.5.2.4 {
execsql {
SELECT * FROM av4 WHERE a = 'av4 a' AND b = 'av4 b' AND c = 'av4 c';
}
} {{av4 a} {av4 b} {av4 c}}
# Drop table av3. Indices av4_i2, av4_i3 and av4_i4 are moved to fill the two
# root pages vacated. The operation proceeds as:
# Step 1: Delete av3_i1 (root-page 11). Move root-page of av4_i4 to page 11.
# Step 2: Delete av3 (root-page 10). Move root-page of av4_i3 to page 10.
# Step 3: Delete sqlite_autoindex_av1_3 (root-page 9). Move av4_i2 to page 9.
do_test autovacuum-2.5.3 {
execsql {
DROP TABLE av3;
SELECT name, rootpage FROM sqlite_master;
}
} [list av1 3 sqlite_autoindex_av1_1 4 \
av2 5 sqlite_autoindex_av2_1 6 av2_i1 7 av2_i2 8 \
av4 12 av4_i1 13 av4_i2 9 av4_i3 10 av4_i4 11 \
]
do_test autovacuum-2.5.3.1 {
execsql {
SELECT * FROM av1 WHERE a = 'av1 a';
}
} {{av1 a} {av1 b} {av1 c}}
do_test autovacuum-2.5.3.2 {
execsql {
SELECT * FROM av2 WHERE a = 'av2 a' AND b = 'av2 b' AND c = 'av2 c'
}
} {{av2 a} {av2 b} {av2 c}}
do_test autovacuum-2.5.3.3 {
execsql {
SELECT * FROM av4 WHERE a = 'av4 a' AND b = 'av4 b' AND c = 'av4 c';
}
} {{av4 a} {av4 b} {av4 c}}
# Drop table av1:
# Step 1: Delete av1 (root page 4). Root-page of av4_i1 fills the gap.
# Step 2: Delete sqlite_autoindex_av1_1 (root page 3). Move av4 to the gap.
do_test autovacuum-2.5.4 {
execsql {
DROP TABLE av1;
SELECT name, rootpage FROM sqlite_master;
}
} [list av2 5 sqlite_autoindex_av2_1 6 av2_i1 7 av2_i2 8 \
av4 3 av4_i1 4 av4_i2 9 av4_i3 10 av4_i4 11 \
]
do_test autovacuum-2.5.4.2 {
execsql {
SELECT * FROM av2 WHERE a = 'av2 a' AND b = 'av2 b' AND c = 'av2 c'
}
} {{av2 a} {av2 b} {av2 c}}
do_test autovacuum-2.5.4.4 {
execsql {
SELECT * FROM av4 WHERE a = 'av4 a' AND b = 'av4 b' AND c = 'av4 c';
}
} {{av4 a} {av4 b} {av4 c}}
# Drop table av4:
# Step 1: Delete av4_i4.
# Step 2: Delete av4_i3.
# Step 3: Delete av4_i2.
# Step 4: Delete av4_i1. av2_i2 replaces it.
# Step 5: Delete av4. av2_i1 replaces it.
do_test autovacuum-2.5.5 {
execsql {
DROP TABLE av4;
SELECT name, rootpage FROM sqlite_master;
}
} [list av2 5 sqlite_autoindex_av2_1 6 av2_i1 3 av2_i2 4]
do_test autovacuum-2.5.5.2 {
execsql {
SELECT * FROM av2 WHERE a = 'av2 a' AND b = 'av2 b' AND c = 'av2 c'
}
} {{av2 a} {av2 b} {av2 c}}
#--------------------------------------------------------------------------
# Test cases autovacuum-3.* test the operation of the "PRAGMA auto_vacuum"
# command.
#
do_test autovacuum-3.1 {
execsql {
PRAGMA auto_vacuum;
}
} {1}
do_test autovacuum-3.2 {
db close
sqlite3 db test.db
execsql {
PRAGMA auto_vacuum;
}
} {1}
do_test autovacuum-3.3 {
execsql {
PRAGMA auto_vacuum = 0;
PRAGMA auto_vacuum;
}
} {1}
do_test autovacuum-3.4 {
db close
file delete -force test.db
sqlite3 db test.db
execsql {
PRAGMA auto_vacuum;
}
} $AUTOVACUUM
do_test autovacuum-3.5 {
execsql {
CREATE TABLE av1(x);
PRAGMA auto_vacuum;
}
} $AUTOVACUUM
do_test autovacuum-3.6 {
execsql {
PRAGMA auto_vacuum = 1;
PRAGMA auto_vacuum;
}
} $AUTOVACUUM
do_test autovacuum-3.7 {
execsql {
DROP TABLE av1;
}
file_pages
} [expr $AUTOVACUUM?1:2]
#-----------------------------------------------------------------------
# Test that if a statement transaction around a CREATE INDEX statement is
# rolled back no corruption occurs.
#
do_test autovacuum-4.1 {
execsql {
CREATE TABLE av1(a, b);
BEGIN;
}
for {set i 0} {$i<100} {incr i} {
execsql "INSERT INTO av1 VALUES($i, '[string repeat X 200]');"
}
execsql "INSERT INTO av1 VALUES(99, '[string repeat X 200]');"
execsql {
SELECT sum(a) FROM av1;
}
} {5049}
do_test autovacuum-4.2 {
catchsql {
CREATE UNIQUE INDEX av1_i ON av1(a);
}
} {1 {indexed columns are not unique}}
do_test autovacuum-4.3 {
execsql {
SELECT sum(a) FROM av1;
}
} {5049}
do_test autovacuum-4.4 {
execsql {
COMMIT;
}
} {}
ifcapable integrityck {
# Ticket #1727
do_test autovacuum-5.1 {
db close
sqlite3 db :memory:
db eval {
PRAGMA auto_vacuum=1;
CREATE TABLE t1(a);
CREATE TABLE t2(a);
DROP TABLE t1;
PRAGMA integrity_check;
}
} ok
}
# Ticket #1728.
#
# In autovacuum mode, when tables or indices are deleted, the rootpage
# values in the symbol table have to be updated. There was a bug in this
# logic so that if an index/table was moved twice, the second move might
# not occur. This would leave the internal symbol table in an inconsistent
# state causing subsequent statements to fail.
#
# The problem is difficult to reproduce. The sequence of statements in
# the following test are carefully designed make it occur and thus to
# verify that this very obscure bug has been resolved.
#
ifcapable integrityck&&memorydb {
do_test autovacuum-6.1 {
db close
sqlite3 db :memory:
db eval {
PRAGMA auto_vacuum=1;
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE TABLE t2(a);
CREATE INDEX i2 ON t2(a);
CREATE TABLE t3(a);
CREATE INDEX i3 ON t2(a);
CREATE INDEX x ON t1(b);
DROP TABLE t3;
PRAGMA integrity_check;
DROP TABLE t2;
PRAGMA integrity_check;
DROP TABLE t1;
PRAGMA integrity_check;
}
} {ok ok ok}
}
finish_test
+58
View File
@@ -0,0 +1,58 @@
# 2001 September 15
#
# 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 runs the tests in the file crash.test with auto-vacuum enabled
# databases.
#
# $Id: autovacuum_crash.test,v 1.2 2005/01/16 09:06:34 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum} {
finish_test
return
}
rename finish_test really_finish_test2
proc finish_test {} {}
set ISQUICK 1
rename sqlite3 real_sqlite3
proc sqlite3 {args} {
set r [eval "real_sqlite3 $args"]
if { [llength $args] == 2 } {
[lindex $args 0] eval {pragma auto_vacuum = 1}
}
set r
}
rename do_test really_do_test
proc do_test {args} {
set sc [concat really_do_test "autovacuum-[lindex $args 0]" \
[lrange $args 1 end]]
eval $sc
}
source $testdir/crash.test
rename sqlite3 ""
rename real_sqlite3 sqlite3
rename finish_test ""
rename really_finish_test2 finish_test
rename do_test ""
rename really_do_test do_test
finish_test
+58
View File
@@ -0,0 +1,58 @@
# 2001 September 15
#
# 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 runs the tests in the file ioerr.test with auto-vacuum enabled
# databases.
#
# $Id: autovacuum_ioerr.test,v 1.3 2006/01/16 12:46:41 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum} {
finish_test
return
}
rename finish_test really_finish_test2
proc finish_test {} {}
set ISQUICK 1
rename sqlite3 real_sqlite3
proc sqlite3 {args} {
set r [eval "real_sqlite3 $args"]
if { [llength $args] == 2 } {
[lindex $args 0] eval {pragma auto_vacuum = 1}
}
set r
}
rename do_test really_do_test
proc do_test {args} {
set sc [concat really_do_test "autovacuum-[lindex $args 0]" \
[lrange $args 1 end]]
eval $sc
}
source $testdir/ioerr.test
rename sqlite3 ""
rename real_sqlite3 sqlite3
rename finish_test ""
rename really_finish_test2 finish_test
rename do_test ""
rename really_do_test do_test
finish_test
+120
View File
@@ -0,0 +1,120 @@
# 2001 October 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
#
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: autovacuum_ioerr2.test,v 1.5 2005/01/29 09:14:05 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If this build of the library does not support auto-vacuum, omit this
# whole file.
ifcapable {!autovacuum} {
finish_test
return
}
do_ioerr_test autovacuum-ioerr2-1 -sqlprep {
PRAGMA auto_vacuum = 1;
CREATE TABLE abc(a);
INSERT INTO abc VALUES(randstr(1500,1500));
} -sqlbody {
CREATE TABLE abc2(a);
BEGIN;
DELETE FROM abc;
INSERT INTO abc VALUES(randstr(1500,1500));
CREATE TABLE abc3(a);
COMMIT;
}
do_ioerr_test autovacuum-ioerr2-2 -tclprep {
execsql {
PRAGMA auto_vacuum = 1;
PRAGMA cache_size = 10;
BEGIN;
CREATE TABLE abc(a);
INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 4 is overflow
INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 5 is overflow
}
for {set i 0} {$i<150} {incr i} {
execsql {
INSERT INTO abc VALUES(randstr(100,100));
}
}
execsql COMMIT
} -sqlbody {
BEGIN;
DELETE FROM abc WHERE length(a)>100;
UPDATE abc SET a = randstr(90,90);
CREATE TABLE abc3(a);
COMMIT;
}
do_ioerr_test autovacuum-ioerr2-3 -sqlprep {
PRAGMA auto_vacuum = 1;
CREATE TABLE abc(a);
CREATE TABLE abc2(b);
} -sqlbody {
BEGIN;
INSERT INTO abc2 VALUES(10);
DROP TABLE abc;
COMMIT;
DROP TABLE abc2;
}
file delete -force backup.db
ifcapable subquery {
do_ioerr_test autovacuum-ioerr2-4 -tclprep {
if {![file exists backup.db]} {
sqlite3 dbb backup.db
execsql {
PRAGMA auto_vacuum = 1;
BEGIN;
CREATE TABLE abc(a);
INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 4 is overflow
INSERT INTO abc VALUES(randstr(1100,1100)); -- Page 5 is overflow
} dbb
for {set i 0} {$i<2500} {incr i} {
execsql {
INSERT INTO abc VALUES(randstr(100,100));
} dbb
}
execsql {
COMMIT;
PRAGMA cache_size = 10;
} dbb
dbb close
}
db close
file delete -force test.db
file delete -force test.db-journal
copy_file backup.db test.db
set ::DB [sqlite3 db test.db]
execsql {
PRAGMA cache_size = 10;
}
} -sqlbody {
BEGIN;
DELETE FROM abc WHERE oid < 3;
UPDATE abc SET a = randstr(100,100) WHERE oid > 2300;
UPDATE abc SET a = randstr(1100,1100) WHERE oid =
(select max(oid) from abc);
COMMIT;
}
}
finish_test
+919
View File
@@ -0,0 +1,919 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. This
# file is a copy of "trans.test" modified to run under autovacuum mode.
# the point is to stress the autovacuum logic and try to get it to fail.
#
# $Id: avtrans.test,v 1.4 2006/02/11 01:25:51 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create several tables to work with.
#
do_test avtrans-1.0 {
execsql {
PRAGMA auto_vacuum=ON;
CREATE TABLE one(a int PRIMARY KEY, b text);
INSERT INTO one VALUES(1,'one');
INSERT INTO one VALUES(2,'two');
INSERT INTO one VALUES(3,'three');
SELECT b FROM one ORDER BY a;
}
} {one two three}
do_test avtrans-1.1 {
execsql {
CREATE TABLE two(a int PRIMARY KEY, b text);
INSERT INTO two VALUES(1,'I');
INSERT INTO two VALUES(5,'V');
INSERT INTO two VALUES(10,'X');
SELECT b FROM two ORDER BY a;
}
} {I V X}
do_test avtrans-1.9 {
sqlite3 altdb test.db
execsql {SELECT b FROM one ORDER BY a} altdb
} {one two three}
do_test avtrans-1.10 {
execsql {SELECT b FROM two ORDER BY a} altdb
} {I V X}
integrity_check avtrans-1.11
# Basic transactions
#
do_test avtrans-2.1 {
set v [catch {execsql {BEGIN}} msg]
lappend v $msg
} {0 {}}
do_test avtrans-2.2 {
set v [catch {execsql {END}} msg]
lappend v $msg
} {0 {}}
do_test avtrans-2.3 {
set v [catch {execsql {BEGIN TRANSACTION}} msg]
lappend v $msg
} {0 {}}
do_test avtrans-2.4 {
set v [catch {execsql {COMMIT TRANSACTION}} msg]
lappend v $msg
} {0 {}}
do_test avtrans-2.5 {
set v [catch {execsql {BEGIN TRANSACTION 'foo'}} msg]
lappend v $msg
} {0 {}}
do_test avtrans-2.6 {
set v [catch {execsql {ROLLBACK TRANSACTION 'foo'}} msg]
lappend v $msg
} {0 {}}
do_test avtrans-2.10 {
execsql {
BEGIN;
SELECT a FROM one ORDER BY a;
SELECT a FROM two ORDER BY a;
END;
}
} {1 2 3 1 5 10}
integrity_check avtrans-2.11
# Check the locking behavior
#
do_test avtrans-3.1 {
execsql {
BEGIN;
UPDATE one SET a = 0 WHERE 0;
SELECT a FROM one ORDER BY a;
}
} {1 2 3}
do_test avtrans-3.2 {
catchsql {
SELECT a FROM two ORDER BY a;
} altdb
} {0 {1 5 10}}
do_test avtrans-3.3 {
catchsql {
SELECT a FROM one ORDER BY a;
} altdb
} {0 {1 2 3}}
do_test avtrans-3.4 {
catchsql {
INSERT INTO one VALUES(4,'four');
}
} {0 {}}
do_test avtrans-3.5 {
catchsql {
SELECT a FROM two ORDER BY a;
} altdb
} {0 {1 5 10}}
do_test avtrans-3.6 {
catchsql {
SELECT a FROM one ORDER BY a;
} altdb
} {0 {1 2 3}}
do_test avtrans-3.7 {
catchsql {
INSERT INTO two VALUES(4,'IV');
}
} {0 {}}
do_test avtrans-3.8 {
catchsql {
SELECT a FROM two ORDER BY a;
} altdb
} {0 {1 5 10}}
do_test avtrans-3.9 {
catchsql {
SELECT a FROM one ORDER BY a;
} altdb
} {0 {1 2 3}}
do_test avtrans-3.10 {
execsql {END TRANSACTION}
} {}
do_test avtrans-3.11 {
set v [catch {execsql {
SELECT a FROM two ORDER BY a;
} altdb} msg]
lappend v $msg
} {0 {1 4 5 10}}
do_test avtrans-3.12 {
set v [catch {execsql {
SELECT a FROM one ORDER BY a;
} altdb} msg]
lappend v $msg
} {0 {1 2 3 4}}
do_test avtrans-3.13 {
set v [catch {execsql {
SELECT a FROM two ORDER BY a;
} db} msg]
lappend v $msg
} {0 {1 4 5 10}}
do_test avtrans-3.14 {
set v [catch {execsql {
SELECT a FROM one ORDER BY a;
} db} msg]
lappend v $msg
} {0 {1 2 3 4}}
integrity_check avtrans-3.15
do_test avtrans-4.1 {
set v [catch {execsql {
COMMIT;
} db} msg]
lappend v $msg
} {1 {cannot commit - no transaction is active}}
do_test avtrans-4.2 {
set v [catch {execsql {
ROLLBACK;
} db} msg]
lappend v $msg
} {1 {cannot rollback - no transaction is active}}
do_test avtrans-4.3 {
catchsql {
BEGIN TRANSACTION;
UPDATE two SET a = 0 WHERE 0;
SELECT a FROM two ORDER BY a;
} db
} {0 {1 4 5 10}}
do_test avtrans-4.4 {
catchsql {
SELECT a FROM two ORDER BY a;
} altdb
} {0 {1 4 5 10}}
do_test avtrans-4.5 {
catchsql {
SELECT a FROM one ORDER BY a;
} altdb
} {0 {1 2 3 4}}
do_test avtrans-4.6 {
catchsql {
BEGIN TRANSACTION;
SELECT a FROM one ORDER BY a;
} db
} {1 {cannot start a transaction within a transaction}}
do_test avtrans-4.7 {
catchsql {
SELECT a FROM two ORDER BY a;
} altdb
} {0 {1 4 5 10}}
do_test avtrans-4.8 {
catchsql {
SELECT a FROM one ORDER BY a;
} altdb
} {0 {1 2 3 4}}
do_test avtrans-4.9 {
set v [catch {execsql {
END TRANSACTION;
SELECT a FROM two ORDER BY a;
} db} msg]
lappend v $msg
} {0 {1 4 5 10}}
do_test avtrans-4.10 {
set v [catch {execsql {
SELECT a FROM two ORDER BY a;
} altdb} msg]
lappend v $msg
} {0 {1 4 5 10}}
do_test avtrans-4.11 {
set v [catch {execsql {
SELECT a FROM one ORDER BY a;
} altdb} msg]
lappend v $msg
} {0 {1 2 3 4}}
integrity_check avtrans-4.12
do_test avtrans-4.98 {
altdb close
execsql {
DROP TABLE one;
DROP TABLE two;
}
} {}
integrity_check avtrans-4.99
# Check out the commit/rollback behavior of the database
#
do_test avtrans-5.1 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test avtrans-5.2 {
execsql {BEGIN TRANSACTION}
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test avtrans-5.3 {
execsql {CREATE TABLE one(a text, b int)}
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {one}
do_test avtrans-5.4 {
execsql {SELECT a,b FROM one ORDER BY b}
} {}
do_test avtrans-5.5 {
execsql {INSERT INTO one(a,b) VALUES('hello', 1)}
execsql {SELECT a,b FROM one ORDER BY b}
} {hello 1}
do_test avtrans-5.6 {
execsql {ROLLBACK}
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test avtrans-5.7 {
set v [catch {
execsql {SELECT a,b FROM one ORDER BY b}
} msg]
lappend v $msg
} {1 {no such table: one}}
# Test commits and rollbacks of table CREATE TABLEs, CREATE INDEXs
# DROP TABLEs and DROP INDEXs
#
do_test avtrans-5.8 {
execsql {
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name
}
} {}
do_test avtrans-5.9 {
execsql {
BEGIN TRANSACTION;
CREATE TABLE t1(a int, b int, c int);
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {t1}
do_test avtrans-5.10 {
execsql {
CREATE INDEX i1 ON t1(a);
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i1 t1}
do_test avtrans-5.11 {
execsql {
COMMIT;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i1 t1}
do_test avtrans-5.12 {
execsql {
BEGIN TRANSACTION;
CREATE TABLE t2(a int, b int, c int);
CREATE INDEX i2a ON t2(a);
CREATE INDEX i2b ON t2(b);
DROP TABLE t1;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i2a i2b t2}
do_test avtrans-5.13 {
execsql {
ROLLBACK;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i1 t1}
do_test avtrans-5.14 {
execsql {
BEGIN TRANSACTION;
DROP INDEX i1;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {t1}
do_test avtrans-5.15 {
execsql {
ROLLBACK;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i1 t1}
do_test avtrans-5.16 {
execsql {
BEGIN TRANSACTION;
DROP INDEX i1;
CREATE TABLE t2(x int, y int, z int);
CREATE INDEX i2x ON t2(x);
CREATE INDEX i2y ON t2(y);
INSERT INTO t2 VALUES(1,2,3);
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i2x i2y t1 t2}
do_test avtrans-5.17 {
execsql {
COMMIT;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i2x i2y t1 t2}
do_test avtrans-5.18 {
execsql {
SELECT * FROM t2;
}
} {1 2 3}
do_test avtrans-5.19 {
execsql {
SELECT x FROM t2 WHERE y=2;
}
} {1}
do_test avtrans-5.20 {
execsql {
BEGIN TRANSACTION;
DROP TABLE t1;
DROP TABLE t2;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {}
do_test avtrans-5.21 {
set r [catch {execsql {
SELECT * FROM t2
}} msg]
lappend r $msg
} {1 {no such table: t2}}
do_test avtrans-5.22 {
execsql {
ROLLBACK;
SELECT name fROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name;
}
} {i2x i2y t1 t2}
do_test avtrans-5.23 {
execsql {
SELECT * FROM t2;
}
} {1 2 3}
integrity_check avtrans-5.23
# Try to DROP and CREATE tables and indices with the same name
# within a transaction. Make sure ROLLBACK works.
#
do_test avtrans-6.1 {
execsql2 {
INSERT INTO t1 VALUES(1,2,3);
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(p,q,r);
ROLLBACK;
SELECT * FROM t1;
}
} {a 1 b 2 c 3}
do_test avtrans-6.2 {
execsql2 {
INSERT INTO t1 VALUES(1,2,3);
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(p,q,r);
COMMIT;
SELECT * FROM t1;
}
} {}
do_test avtrans-6.3 {
execsql2 {
INSERT INTO t1 VALUES(1,2,3);
SELECT * FROM t1;
}
} {p 1 q 2 r 3}
do_test avtrans-6.4 {
execsql2 {
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(4,5,6);
SELECT * FROM t1;
DROP TABLE t1;
}
} {a 4 b 5 c 6}
do_test avtrans-6.5 {
execsql2 {
ROLLBACK;
SELECT * FROM t1;
}
} {p 1 q 2 r 3}
do_test avtrans-6.6 {
execsql2 {
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(4,5,6);
SELECT * FROM t1;
DROP TABLE t1;
}
} {a 4 b 5 c 6}
do_test avtrans-6.7 {
catchsql {
COMMIT;
SELECT * FROM t1;
}
} {1 {no such table: t1}}
# Repeat on a table with an automatically generated index.
#
do_test avtrans-6.10 {
execsql2 {
CREATE TABLE t1(a unique,b,c);
INSERT INTO t1 VALUES(1,2,3);
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(p unique,q,r);
ROLLBACK;
SELECT * FROM t1;
}
} {a 1 b 2 c 3}
do_test avtrans-6.11 {
execsql2 {
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(p unique,q,r);
COMMIT;
SELECT * FROM t1;
}
} {}
do_test avtrans-6.12 {
execsql2 {
INSERT INTO t1 VALUES(1,2,3);
SELECT * FROM t1;
}
} {p 1 q 2 r 3}
do_test avtrans-6.13 {
execsql2 {
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(a unique,b,c);
INSERT INTO t1 VALUES(4,5,6);
SELECT * FROM t1;
DROP TABLE t1;
}
} {a 4 b 5 c 6}
do_test avtrans-6.14 {
execsql2 {
ROLLBACK;
SELECT * FROM t1;
}
} {p 1 q 2 r 3}
do_test avtrans-6.15 {
execsql2 {
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(a unique,b,c);
INSERT INTO t1 VALUES(4,5,6);
SELECT * FROM t1;
DROP TABLE t1;
}
} {a 4 b 5 c 6}
do_test avtrans-6.16 {
catchsql {
COMMIT;
SELECT * FROM t1;
}
} {1 {no such table: t1}}
do_test avtrans-6.20 {
execsql {
CREATE TABLE t1(a integer primary key,b,c);
INSERT INTO t1 VALUES(1,-2,-3);
INSERT INTO t1 VALUES(4,-5,-6);
SELECT * FROM t1;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.21 {
execsql {
CREATE INDEX i1 ON t1(b);
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.22 {
execsql {
BEGIN TRANSACTION;
DROP INDEX i1;
SELECT * FROM t1 WHERE b<1;
ROLLBACK;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.23 {
execsql {
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.24 {
execsql {
BEGIN TRANSACTION;
DROP TABLE t1;
ROLLBACK;
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.25 {
execsql {
BEGIN TRANSACTION;
DROP INDEX i1;
CREATE INDEX i1 ON t1(c);
SELECT * FROM t1 WHERE b<1;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.26 {
execsql {
SELECT * FROM t1 WHERE c<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.27 {
execsql {
ROLLBACK;
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.28 {
execsql {
SELECT * FROM t1 WHERE c<1;
}
} {1 -2 -3 4 -5 -6}
# The following repeats steps 6.20 through 6.28, but puts a "unique"
# constraint the first field of the table in order to generate an
# automatic index.
#
do_test avtrans-6.30 {
execsql {
BEGIN TRANSACTION;
DROP TABLE t1;
CREATE TABLE t1(a int unique,b,c);
COMMIT;
INSERT INTO t1 VALUES(1,-2,-3);
INSERT INTO t1 VALUES(4,-5,-6);
SELECT * FROM t1 ORDER BY a;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.31 {
execsql {
CREATE INDEX i1 ON t1(b);
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.32 {
execsql {
BEGIN TRANSACTION;
DROP INDEX i1;
SELECT * FROM t1 WHERE b<1;
ROLLBACK;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.33 {
execsql {
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.34 {
execsql {
BEGIN TRANSACTION;
DROP TABLE t1;
ROLLBACK;
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.35 {
execsql {
BEGIN TRANSACTION;
DROP INDEX i1;
CREATE INDEX i1 ON t1(c);
SELECT * FROM t1 WHERE b<1;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.36 {
execsql {
SELECT * FROM t1 WHERE c<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.37 {
execsql {
DROP INDEX i1;
SELECT * FROM t1 WHERE c<1;
}
} {1 -2 -3 4 -5 -6}
do_test avtrans-6.38 {
execsql {
ROLLBACK;
SELECT * FROM t1 WHERE b<1;
}
} {4 -5 -6 1 -2 -3}
do_test avtrans-6.39 {
execsql {
SELECT * FROM t1 WHERE c<1;
}
} {1 -2 -3 4 -5 -6}
integrity_check avtrans-6.40
ifcapable !floatingpoint {
finish_test
return
}
# Test to make sure rollback restores the database back to its original
# state.
#
do_test avtrans-7.1 {
execsql {BEGIN}
for {set i 0} {$i<1000} {incr i} {
set r1 [expr {rand()}]
set r2 [expr {rand()}]
set r3 [expr {rand()}]
execsql "INSERT INTO t2 VALUES($r1,$r2,$r3)"
}
execsql {COMMIT}
set ::checksum [execsql {SELECT md5sum(x,y,z) FROM t2}]
set ::checksum2 [
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
]
execsql {SELECT count(*) FROM t2}
} {1001}
do_test avtrans-7.2 {
execsql {SELECT md5sum(x,y,z) FROM t2}
} $checksum
do_test avtrans-7.2.1 {
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
} $checksum2
do_test avtrans-7.3 {
execsql {
BEGIN;
DELETE FROM t2;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
do_test avtrans-7.4 {
execsql {
BEGIN;
INSERT INTO t2 SELECT * FROM t2;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
do_test avtrans-7.5 {
execsql {
BEGIN;
DELETE FROM t2;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
do_test avtrans-7.6 {
execsql {
BEGIN;
INSERT INTO t2 SELECT * FROM t2;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
do_test avtrans-7.7 {
execsql {
BEGIN;
CREATE TABLE t3 AS SELECT * FROM t2;
INSERT INTO t2 SELECT * FROM t3;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
do_test avtrans-7.8 {
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
} $checksum2
ifcapable tempdb {
do_test avtrans-7.9 {
execsql {
BEGIN;
CREATE TEMP TABLE t3 AS SELECT * FROM t2;
INSERT INTO t2 SELECT * FROM t3;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
}
do_test avtrans-7.10 {
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
} $checksum2
ifcapable tempdb {
do_test avtrans-7.11 {
execsql {
BEGIN;
CREATE TEMP TABLE t3 AS SELECT * FROM t2;
INSERT INTO t2 SELECT * FROM t3;
DROP INDEX i2x;
DROP INDEX i2y;
CREATE INDEX i3a ON t3(x);
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
}
do_test avtrans-7.12 {
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
} $checksum2
ifcapable tempdb {
do_test avtrans-7.13 {
execsql {
BEGIN;
DROP TABLE t2;
ROLLBACK;
SELECT md5sum(x,y,z) FROM t2;
}
} $checksum
}
do_test avtrans-7.14 {
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
} $checksum2
integrity_check avtrans-7.15
# Arrange for another process to begin modifying the database but abort
# and die in the middle of the modification. Then have this process read
# the database. This process should detect the journal file and roll it
# back. Verify that this happens correctly.
#
set fd [open test.tcl w]
puts $fd {
sqlite3 db test.db
db eval {
PRAGMA default_cache_size=20;
BEGIN;
CREATE TABLE t3 AS SELECT * FROM t2;
DELETE FROM t2;
}
sqlite_abort
}
close $fd
do_test avtrans-8.1 {
catch {exec [info nameofexec] test.tcl}
execsql {SELECT md5sum(x,y,z) FROM t2}
} $checksum
do_test avtrans-8.2 {
execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
} $checksum2
integrity_check avtrans-8.3
# In the following sequence of tests, compute the MD5 sum of the content
# of a table, make lots of modifications to that table, then do a rollback.
# Verify that after the rollback, the MD5 checksum is unchanged.
#
do_test avtrans-9.1 {
execsql {
PRAGMA default_cache_size=10;
}
db close
sqlite3 db test.db
execsql {
BEGIN;
CREATE TABLE t3(x TEXT);
INSERT INTO t3 VALUES(randstr(10,400));
INSERT INTO t3 VALUES(randstr(10,400));
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
INSERT INTO t3 SELECT randstr(10,400) FROM t3;
COMMIT;
SELECT count(*) FROM t3;
}
} {1024}
# The following procedure computes a "signature" for table "t3". If
# T3 changes in any way, the signature should change.
#
# This is used to test ROLLBACK. We gather a signature for t3, then
# make lots of changes to t3, then rollback and take another signature.
# The two signatures should be the same.
#
proc signature {} {
return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}
# Repeat the following group of tests 20 times for quick testing and
# 40 times for full testing. Each iteration of the test makes table
# t3 a little larger, and thus takes a little longer, so doing 40 tests
# is more than 2.0 times slower than doing 20 tests. Considerably more.
#
if {[info exists ISQUICK]} {
set limit 20
} else {
set limit 40
}
# Do rollbacks. Make sure the signature does not change.
#
for {set i 2} {$i<=$limit} {incr i} {
set ::sig [signature]
set cnt [lindex $::sig 0]
if {$i%2==0} {
execsql {PRAGMA fullfsync=ON}
} else {
execsql {PRAGMA fullfsync=OFF}
}
set sqlite_sync_count 0
set sqlite_fullsync_count 0
do_test avtrans-9.$i.1-$cnt {
execsql {
BEGIN;
DELETE FROM t3 WHERE random()%10!=0;
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
ROLLBACK;
}
signature
} $sig
do_test avtrans-9.$i.2-$cnt {
execsql {
BEGIN;
DELETE FROM t3 WHERE random()%10!=0;
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
DELETE FROM t3 WHERE random()%10!=0;
INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
ROLLBACK;
}
signature
} $sig
if {$i<$limit} {
do_test avtrans-9.$i.3-$cnt {
execsql {
INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE random()%10==0;
}
} {}
if {$tcl_platform(platform)=="unix"} {
do_test avtrans-9.$i.4-$cnt {
expr {$sqlite_sync_count>0}
} 1
ifcapable pager_pragmas {
do_test avtrans-9.$i.5-$cnt {
expr {$sqlite_fullsync_count>0}
} [expr {$i%2==0}]
} else {
do_test avtrans-9.$i.5-$cnt {
expr {$sqlite_fullsync_count>0}
} {1}
}
}
}
set ::pager_old_format 0
}
integrity_check avtrans-10.1
finish_test
+113
View File
@@ -0,0 +1,113 @@
# 2005 July 28
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the use of indices in WHERE clauses
# when the WHERE clause contains the BETWEEN operator.
#
# $Id: between.test,v 1.2 2006/01/17 09:35:02 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Build some test data
#
do_test between-1.0 {
execsql {
BEGIN;
CREATE TABLE t1(w int, x int, y int, z int);
}
for {set i 1} {$i<=100} {incr i} {
set w $i
set x [expr {int(log($i)/log(2))}]
set y [expr {$i*$i + 2*$i + 1}]
set z [expr {$x+$y}]
ifcapable tclvar {
# Random unplanned test of the $varname variable syntax.
execsql {INSERT INTO t1 VALUES($::w,$::x,$::y,$::z)}
} else {
# If the $varname syntax is not available, use the regular variable
# declaration syntax.
execsql {INSERT INTO t1 VALUES(:w,:x,:y,:z)}
}
}
execsql {
CREATE UNIQUE INDEX i1w ON t1(w);
CREATE INDEX i1xy ON t1(x,y);
CREATE INDEX i1zyx ON t1(z,y,x);
COMMIT;
}
} {}
# This procedure executes the SQL. Then it appends to the result the
# "sort" or "nosort" keyword depending on whether or not any sorting
# is done. Then it appends the ::sqlite_query_plan variable.
#
proc queryplan {sql} {
set ::sqlite_sort_count 0
set data [execsql $sql]
if {$::sqlite_sort_count} {set x sort} {set x nosort}
lappend data $x
return [concat $data $::sqlite_query_plan]
}
do_test between-1.1.1 {
queryplan {
SELECT * FROM t1 WHERE w BETWEEN 5 AND 6 ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 i1w}
do_test between-1.1.2 {
queryplan {
SELECT * FROM t1 WHERE +w BETWEEN 5 AND 6 ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 {}}
do_test between-1.2.1 {
queryplan {
SELECT * FROM t1 WHERE w BETWEEN 5 AND 65-y ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 i1w}
do_test between-1.2.2 {
queryplan {
SELECT * FROM t1 WHERE +w BETWEEN 5 AND 65-y ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 {}}
do_test between-1.3.1 {
queryplan {
SELECT * FROM t1 WHERE w BETWEEN 41-y AND 6 ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 i1w}
do_test between-1.3.2 {
queryplan {
SELECT * FROM t1 WHERE +w BETWEEN 41-y AND 6 ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 {}}
do_test between-1.4 {
queryplan {
SELECT * FROM t1 WHERE w BETWEEN 41-y AND 65-y ORDER BY +w
}
} {5 2 36 38 6 2 49 51 sort t1 {}}
do_test between-1.5.1 {
queryplan {
SELECT * FROM t1 WHERE 26 BETWEEN y AND z ORDER BY +w
}
} {4 2 25 27 sort t1 i1zyx}
do_test between-1.5.2 {
queryplan {
SELECT * FROM t1 WHERE 26 BETWEEN +y AND z ORDER BY +w
}
} {4 2 25 27 sort t1 i1zyx}
do_test between-1.5.3 {
queryplan {
SELECT * FROM t1 WHERE 26 BETWEEN y AND +z ORDER BY +w
}
} {4 2 25 27 sort t1 {}}
finish_test
+192
View File
@@ -0,0 +1,192 @@
# 2002 November 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 regression tests for SQLite library. The
# focus of this script testing the ability of SQLite to handle database
# files larger than 4GB.
#
# $Id: bigfile.test,v 1.9 2005/11/25 09:01:24 danielk1977 Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_DISABLE_LFS is defined, omit this file.
ifcapable !lfs {
finish_test
return
}
# These tests only work for Tcl version 8.4 and later. Prior to 8.4,
# Tcl was unable to handle large files.
#
scan $::tcl_version %f vx
if {$vx<8.4} return
# Mac OS X does not handle large files efficiently. So skip this test
# on that platform.
if {$tcl_platform(os)=="Darwin"} return
# This is the md5 checksum of all the data in table t1 as created
# by the first test. We will use this number to make sure that data
# never changes.
#
set MAGIC_SUM {593f1efcfdbe698c28b4b1b693f7e4cf}
do_test bigfile-1.1 {
execsql {
BEGIN;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz');
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
INSERT INTO t1 SELECT rowid || ' ' || x FROM t1;
COMMIT;
}
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
# Try to create a large file - a file that is larger than 2^32 bytes.
# If this fails, it means that the system being tested does not support
# large files. So skip all of the remaining tests in this file.
#
db close
if {[catch {fake_big_file 4096 test.db}]} {
puts "**** Unable to create a file larger than 4096 MB. *****"
finish_test
return
}
do_test bigfile-1.2 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
# The previous test may fail on some systems because they are unable
# to handle large files. If that is so, then skip all of the following
# tests. We will know the above test failed because the "db" command
# does not exist.
#
if {[llength [info command db]]>0} {
do_test bigfile-1.3 {
execsql {
CREATE TABLE t2 AS SELECT * FROM t1;
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.4 {
db close
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.5 {
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
db close
if {[catch {fake_big_file 8192 test.db}]} {
puts "**** Unable to create a file larger than 8192 MB. *****"
finish_test
return
}
do_test bigfile-1.6 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.7 {
execsql {
CREATE TABLE t3 AS SELECT * FROM t1;
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
do_test bigfile-1.8 {
db close
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.9 {
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.10 {
execsql {
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
db close
if {[catch {fake_big_file 16384 test.db}]} {
puts "**** Unable to create a file larger than 16384 MB. *****"
finish_test
return
}
do_test bigfile-1.11 {
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.12 {
execsql {
CREATE TABLE t4 AS SELECT * FROM t1;
SELECT md5sum(x) FROM t4;
}
} $::MAGIC_SUM
do_test bigfile-1.13 {
db close
sqlite3 db test.db
execsql {
SELECT md5sum(x) FROM t1;
}
} $::MAGIC_SUM
do_test bigfile-1.14 {
execsql {
SELECT md5sum(x) FROM t2;
}
} $::MAGIC_SUM
do_test bigfile-1.15 {
execsql {
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
do_test bigfile-1.16 {
execsql {
SELECT md5sum(x) FROM t3;
}
} $::MAGIC_SUM
do_test bigfile-1.17 {
execsql {
SELECT md5sum(x) FROM t4;
}
} $::MAGIC_SUM
} ;# End of the "if( db command exists )"
finish_test
+223
View File
@@ -0,0 +1,223 @@
# 2001 September 23
#
# 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 regression tests for SQLite library. The
# focus of this file is stressing the library by putting large amounts
# of data in a single row of a table.
#
# $Id: bigrow.test,v 1.5 2004/08/07 23:54:48 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Make a big string that we can use for test data
#
do_test bigrow-1.0 {
set ::bigstr {}
for {set i 1} {$i<=9999} {incr i} {
set sep [string index "abcdefghijklmnopqrstuvwxyz" [expr {$i%26}]]
append ::bigstr "$sep [format %04d $i] "
}
string length $::bigstr
} {69993}
# Make a table into which we can insert some but records.
#
do_test bigrow-1.1 {
execsql {
CREATE TABLE t1(a text, b text, c text);
SELECT name FROM sqlite_master
WHERE type='table' OR type='index'
ORDER BY name
}
} {t1}
do_test bigrow-1.2 {
set ::big1 [string range $::bigstr 0 65519]
set sql "INSERT INTO t1 VALUES('abc',"
append sql "'$::big1', 'xyz');"
execsql $sql
execsql {SELECT a, c FROM t1}
} {abc xyz}
do_test bigrow-1.3 {
execsql {SELECT b FROM t1}
} [list $::big1]
do_test bigrow-1.4 {
set ::big2 [string range $::bigstr 0 65520]
set sql "INSERT INTO t1 VALUES('abc2',"
append sql "'$::big2', 'xyz2');"
set r [catch {execsql $sql} msg]
lappend r $msg
} {0 {}}
do_test bigrow-1.4.1 {
execsql {SELECT b FROM t1 ORDER BY c}
} [list $::big1 $::big2]
do_test bigrow-1.4.2 {
execsql {SELECT c FROM t1 ORDER BY c}
} {xyz xyz2}
do_test bigrow-1.4.3 {
execsql {DELETE FROM t1 WHERE a='abc2'}
execsql {SELECT c FROM t1}
} {xyz}
do_test bigrow-1.5 {
execsql {
UPDATE t1 SET a=b, b=a;
SELECT b,c FROM t1
}
} {abc xyz}
do_test bigrow-1.6 {
execsql {
SELECT * FROM t1
}
} [list $::big1 abc xyz]
do_test bigrow-1.7 {
execsql {
INSERT INTO t1 VALUES('1','2','3');
INSERT INTO t1 VALUES('A','B','C');
SELECT b FROM t1 WHERE a=='1';
}
} {2}
do_test bigrow-1.8 {
execsql "SELECT b FROM t1 WHERE a=='$::big1'"
} {abc}
do_test bigrow-1.9 {
execsql "SELECT b FROM t1 WHERE a!='$::big1' ORDER BY a"
} {2 B}
# Try doing some indexing on big columns
#
do_test bigrow-2.1 {
execsql {
CREATE INDEX i1 ON t1(a)
}
execsql "SELECT b FROM t1 WHERE a=='$::big1'"
} {abc}
do_test bigrow-2.2 {
execsql {
UPDATE t1 SET a=b, b=a
}
execsql "SELECT b FROM t1 WHERE a=='abc'"
} [list $::big1]
do_test bigrow-2.3 {
execsql {
UPDATE t1 SET a=b, b=a
}
execsql "SELECT b FROM t1 WHERE a=='$::big1'"
} {abc}
catch {unset ::bigstr}
catch {unset ::big1}
catch {unset ::big2}
# Mosts of the tests above were created back when rows were limited in
# size to 64K. Now rows can be much bigger. Test that logic. Also
# make sure things work correctly at the transition boundries between
# row sizes of 256 to 257 bytes and from 65536 to 65537 bytes.
#
# We begin by testing the 256..257 transition.
#
do_test bigrow-3.1 {
execsql {
DELETE FROM t1;
INSERT INTO t1(a,b,c) VALUES('one','abcdefghijklmnopqrstuvwxyz0123','hi');
}
execsql {SELECT a,length(b),c FROM t1}
} {one 30 hi}
do_test bigrow-3.2 {
execsql {
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
}
execsql {SELECT a,length(b),c FROM t1}
} {one 240 hi}
for {set i 1} {$i<10} {incr i} {
do_test bigrow-3.3.$i {
execsql "UPDATE t1 SET b=b||'$i'"
execsql {SELECT a,length(b),c FROM t1}
} "one [expr {240+$i}] hi"
}
# Now test the 65536..65537 row-size transition.
#
do_test bigrow-4.1 {
execsql {
DELETE FROM t1;
INSERT INTO t1(a,b,c) VALUES('one','abcdefghijklmnopqrstuvwxyz0123','hi');
}
execsql {SELECT a,length(b),c FROM t1}
} {one 30 hi}
do_test bigrow-4.2 {
execsql {
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
UPDATE t1 SET b=b||b;
}
execsql {SELECT a,length(b),c FROM t1}
} {one 122880 hi}
do_test bigrow-4.3 {
execsql {
UPDATE t1 SET b=substr(b,1,65515)
}
execsql {SELECT a,length(b),c FROM t1}
} {one 65515 hi}
for {set i 1} {$i<10} {incr i} {
do_test bigrow-4.4.$i {
execsql "UPDATE t1 SET b=b||'$i'"
execsql {SELECT a,length(b),c FROM t1}
} "one [expr {65515+$i}] hi"
}
# Check to make sure the library recovers safely if a row contains
# too much data.
#
do_test bigrow-5.1 {
execsql {
DELETE FROM t1;
INSERT INTO t1(a,b,c) VALUES('one','abcdefghijklmnopqrstuvwxyz0123','hi');
}
execsql {SELECT a,length(b),c FROM t1}
} {one 30 hi}
set i 1
for {set sz 60} {$sz<1048560} {incr sz $sz} {
do_test bigrow-5.2.$i {
execsql {
UPDATE t1 SET b=b||b;
SELECT a,length(b),c FROM t1;
}
} "one $sz hi"
incr i
}
do_test bigrow-5.3 {
catchsql {UPDATE t1 SET b=b||b}
} {0 {}}
do_test bigrow-5.4 {
execsql {SELECT length(b) FROM t1}
} 1966080
do_test bigrow-5.5 {
catchsql {UPDATE t1 SET b=b||b}
} {0 {}}
do_test bigrow-5.6 {
execsql {SELECT length(b) FROM t1}
} 3932160
do_test bigrow-5.99 {
execsql {DROP TABLE t1}
} {}
finish_test
+559
View File
@@ -0,0 +1,559 @@
# 2003 September 6
#
# 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 regression tests for SQLite library. The
# focus of this script testing the sqlite_bind API.
#
# $Id: bind.test,v 1.38 2006/06/27 20:06:45 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
proc sqlite_step {stmt N VALS COLS} {
upvar VALS vals
upvar COLS cols
set vals [list]
set cols [list]
set rc [sqlite3_step $stmt]
for {set i 0} {$i < [sqlite3_column_count $stmt]} {incr i} {
lappend cols [sqlite3_column_name $stmt $i]
}
for {set i 0} {$i < [sqlite3_data_count $stmt]} {incr i} {
lappend vals [sqlite3_column_text $stmt $i]
}
return $rc
}
do_test bind-1.1 {
set DB [sqlite3_connection_pointer db]
execsql {CREATE TABLE t1(a,b,c);}
set VM [sqlite3_prepare $DB {INSERT INTO t1 VALUES(:1,?,:abc)} -1 TAIL]
set TAIL
} {}
do_test bind-1.1.1 {
sqlite3_bind_parameter_count $VM
} 3
do_test bind-1.1.2 {
sqlite3_bind_parameter_name $VM 1
} {:1}
do_test bind-1.1.3 {
sqlite3_bind_parameter_name $VM 2
} {}
do_test bind-1.1.4 {
sqlite3_bind_parameter_name $VM 3
} {:abc}
do_test bind-1.2 {
sqlite_step $VM N VALUES COLNAMES
} {SQLITE_DONE}
do_test bind-1.3 {
execsql {SELECT rowid, * FROM t1}
} {1 {} {} {}}
do_test bind-1.4 {
sqlite3_reset $VM
sqlite_bind $VM 1 {test value 1} normal
sqlite_step $VM N VALUES COLNAMES
} SQLITE_DONE
do_test bind-1.5 {
execsql {SELECT rowid, * FROM t1}
} {1 {} {} {} 2 {test value 1} {} {}}
do_test bind-1.6 {
sqlite3_reset $VM
sqlite_bind $VM 3 {'test value 2'} normal
sqlite_step $VM N VALUES COLNAMES
} SQLITE_DONE
do_test bind-1.7 {
execsql {SELECT rowid, * FROM t1}
} {1 {} {} {} 2 {test value 1} {} {} 3 {test value 1} {} {'test value 2'}}
do_test bind-1.8 {
sqlite3_reset $VM
set sqlite_static_bind_value 123
sqlite_bind $VM 1 {} static
sqlite_bind $VM 2 {abcdefg} normal
sqlite_bind $VM 3 {} null
execsql {DELETE FROM t1}
sqlite_step $VM N VALUES COLNAMES
execsql {SELECT rowid, * FROM t1}
} {1 123 abcdefg {}}
do_test bind-1.9 {
sqlite3_reset $VM
sqlite_bind $VM 1 {456} normal
sqlite_step $VM N VALUES COLNAMES
execsql {SELECT rowid, * FROM t1}
} {1 123 abcdefg {} 2 456 abcdefg {}}
do_test bind-1.99 {
sqlite3_finalize $VM
} SQLITE_OK
# Prepare the statement in different ways depending on whether or not
# the $var processing is compiled into the library.
#
ifcapable {tclvar} {
do_test bind-2.1 {
execsql {
DELETE FROM t1;
}
set VM [sqlite3_prepare $DB {INSERT INTO t1 VALUES($one,$::two,$x(-z-))}\
-1 TX]
set TX
} {}
set v1 {$one}
set v2 {$::two}
set v3 {$x(-z-)}
}
ifcapable {!tclvar} {
do_test bind-2.1 {
execsql {
DELETE FROM t1;
}
set VM [sqlite3_prepare $DB {INSERT INTO t1 VALUES(:one,:two,:_)} -1 TX]
set TX
} {}
set v1 {:one}
set v2 {:two}
set v3 {:_}
}
do_test bind-2.1.1 {
sqlite3_bind_parameter_count $VM
} 3
do_test bind-2.1.2 {
sqlite3_bind_parameter_name $VM 1
} $v1
do_test bind-2.1.3 {
sqlite3_bind_parameter_name $VM 2
} $v2
do_test bind-2.1.4 {
sqlite3_bind_parameter_name $VM 3
} $v3
do_test bind-2.1.5 {
sqlite3_bind_parameter_index $VM $v1
} 1
do_test bind-2.1.6 {
sqlite3_bind_parameter_index $VM $v2
} 2
do_test bind-2.1.7 {
sqlite3_bind_parameter_index $VM $v3
} 3
do_test bind-2.1.8 {
sqlite3_bind_parameter_index $VM {:hi}
} 0
# 32 bit Integers
do_test bind-2.2 {
sqlite3_bind_int $VM 1 123
sqlite3_bind_int $VM 2 456
sqlite3_bind_int $VM 3 789
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
execsql {SELECT rowid, * FROM t1}
} {1 123 456 789}
do_test bind-2.3 {
sqlite3_bind_int $VM 2 -2000000000
sqlite3_bind_int $VM 3 2000000000
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
execsql {SELECT rowid, * FROM t1}
} {1 123 456 789 2 123 -2000000000 2000000000}
do_test bind-2.4 {
execsql {SELECT typeof(a), typeof(b), typeof(c) FROM t1}
} {integer integer integer integer integer integer}
do_test bind-2.5 {
execsql {
DELETE FROM t1;
}
} {}
# 64 bit Integers
do_test bind-3.1 {
sqlite3_bind_int64 $VM 1 32
sqlite3_bind_int64 $VM 2 -2000000000000
sqlite3_bind_int64 $VM 3 2000000000000
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
execsql {SELECT rowid, * FROM t1}
} {1 32 -2000000000000 2000000000000}
do_test bind-3.2 {
execsql {SELECT typeof(a), typeof(b), typeof(c) FROM t1}
} {integer integer integer}
do_test bind-3.3 {
execsql {
DELETE FROM t1;
}
} {}
# Doubles
do_test bind-4.1 {
sqlite3_bind_double $VM 1 1234.1234
sqlite3_bind_double $VM 2 0.00001
sqlite3_bind_double $VM 3 123456789
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
set x [execsql {SELECT rowid, * FROM t1}]
regsub {1e-005} $x {1e-05} y
set y
} {1 1234.1234 1e-05 123456789.0}
do_test bind-4.2 {
execsql {SELECT typeof(a), typeof(b), typeof(c) FROM t1}
} {real real real}
do_test bind-4.3 {
execsql {
DELETE FROM t1;
}
} {}
# NULL
do_test bind-5.1 {
sqlite3_bind_null $VM 1
sqlite3_bind_null $VM 2
sqlite3_bind_null $VM 3
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
execsql {SELECT rowid, * FROM t1}
} {1 {} {} {}}
do_test bind-5.2 {
execsql {SELECT typeof(a), typeof(b), typeof(c) FROM t1}
} {null null null}
do_test bind-5.3 {
execsql {
DELETE FROM t1;
}
} {}
# UTF-8 text
do_test bind-6.1 {
sqlite3_bind_text $VM 1 hellothere 5
sqlite3_bind_text $VM 2 ".." 1
sqlite3_bind_text $VM 3 world -1
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
execsql {SELECT rowid, * FROM t1}
} {1 hello . world}
do_test bind-6.2 {
execsql {SELECT typeof(a), typeof(b), typeof(c) FROM t1}
} {text text text}
do_test bind-6.3 {
execsql {
DELETE FROM t1;
}
} {}
# UTF-16 text
ifcapable {utf16} {
do_test bind-7.1 {
sqlite3_bind_text16 $VM 1 [encoding convertto unicode hellothere] 10
sqlite3_bind_text16 $VM 2 [encoding convertto unicode ""] 0
sqlite3_bind_text16 $VM 3 [encoding convertto unicode world] 10
sqlite_step $VM N VALUES COLNAMES
sqlite3_reset $VM
execsql {SELECT rowid, * FROM t1}
} {1 hello {} world}
do_test bind-7.2 {
execsql {SELECT typeof(a), typeof(b), typeof(c) FROM t1}
} {text text text}
}
do_test bind-7.3 {
execsql {
DELETE FROM t1;
}
} {}
# Test that the 'out of range' error works.
do_test bind-8.1 {
catch { sqlite3_bind_null $VM 0 }
} {1}
do_test bind-8.2 {
sqlite3_errmsg $DB
} {bind or column index out of range}
ifcapable {utf16} {
do_test bind-8.3 {
encoding convertfrom unicode [sqlite3_errmsg16 $DB]
} {bind or column index out of range}
}
do_test bind-8.4 {
sqlite3_bind_null $VM 1
sqlite3_errmsg $DB
} {not an error}
do_test bind-8.5 {
catch { sqlite3_bind_null $VM 4 }
} {1}
do_test bind-8.6 {
sqlite3_errmsg $DB
} {bind or column index out of range}
ifcapable {utf16} {
do_test bind-8.7 {
encoding convertfrom unicode [sqlite3_errmsg16 $DB]
} {bind or column index out of range}
}
do_test bind-8.8 {
catch { sqlite3_bind_blob $VM 0 "abc" 3 }
} {1}
do_test bind-8.9 {
catch { sqlite3_bind_blob $VM 4 "abc" 3 }
} {1}
do_test bind-8.10 {
catch { sqlite3_bind_text $VM 0 "abc" 3 }
} {1}
ifcapable {utf16} {
do_test bind-8.11 {
catch { sqlite3_bind_text16 $VM 4 "abc" 2 }
} {1}
}
do_test bind-8.12 {
catch { sqlite3_bind_int $VM 0 5 }
} {1}
do_test bind-8.13 {
catch { sqlite3_bind_int $VM 4 5 }
} {1}
do_test bind-8.14 {
catch { sqlite3_bind_double $VM 0 5.0 }
} {1}
do_test bind-8.15 {
catch { sqlite3_bind_double $VM 4 6.0 }
} {1}
do_test bind-8.99 {
sqlite3_finalize $VM
} SQLITE_OK
do_test bind-9.1 {
execsql {
CREATE TABLE t2(a,b,c,d,e,f);
}
set rc [catch {
sqlite3_prepare $DB {
INSERT INTO t2(a) VALUES(?0)
} -1 TAIL
} msg]
lappend rc $msg
} {1 {(1) variable number must be between ?1 and ?999}}
do_test bind-9.2 {
set rc [catch {
sqlite3_prepare $DB {
INSERT INTO t2(a) VALUES(?1000)
} -1 TAIL
} msg]
lappend rc $msg
} {1 {(1) variable number must be between ?1 and ?999}}
do_test bind-9.3 {
set VM [
sqlite3_prepare $DB {
INSERT INTO t2(a,b) VALUES(?1,?999)
} -1 TAIL
]
sqlite3_bind_parameter_count $VM
} {999}
catch {sqlite3_finalize $VM}
do_test bind-9.4 {
set VM [
sqlite3_prepare $DB {
INSERT INTO t2(a,b,c,d) VALUES(?1,?999,?,?)
} -1 TAIL
]
sqlite3_bind_parameter_count $VM
} {1001}
do_test bind-9.5 {
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 999 999
sqlite3_bind_int $VM 1000 1000
sqlite3_bind_int $VM 1001 1001
sqlite3_step $VM
} SQLITE_DONE
do_test bind-9.6 {
sqlite3_finalize $VM
} SQLITE_OK
do_test bind-9.7 {
execsql {SELECT * FROM t2}
} {1 999 1000 1001 {} {}}
ifcapable {tclvar} {
do_test bind-10.1 {
set VM [
sqlite3_prepare $DB {
INSERT INTO t2(a,b,c,d,e,f) VALUES(:abc,$abc,:abc,$ab,$abc,:abc)
} -1 TAIL
]
sqlite3_bind_parameter_count $VM
} 3
set v1 {$abc}
set v2 {$ab}
}
ifcapable {!tclvar} {
do_test bind-10.1 {
set VM [
sqlite3_prepare $DB {
INSERT INTO t2(a,b,c,d,e,f) VALUES(:abc,:xyz,:abc,:xy,:xyz,:abc)
} -1 TAIL
]
sqlite3_bind_parameter_count $VM
} 3
set v1 {:xyz}
set v2 {:xy}
}
do_test bind-10.2 {
sqlite3_bind_parameter_index $VM :abc
} 1
do_test bind-10.3 {
sqlite3_bind_parameter_index $VM $v1
} 2
do_test bind-10.4 {
sqlite3_bind_parameter_index $VM $v2
} 3
do_test bind-10.5 {
sqlite3_bind_parameter_name $VM 1
} :abc
do_test bind-10.6 {
sqlite3_bind_parameter_name $VM 2
} $v1
do_test bind-10.7 {
sqlite3_bind_parameter_name $VM 3
} $v2
do_test bind-10.7.1 {
sqlite3_bind_parameter_name 0 1 ;# Ignore if VM is NULL
} {}
do_test bind-10.7.2 {
sqlite3_bind_parameter_name $VM 0 ;# Ignore if index too small
} {}
do_test bind-10.7.3 {
sqlite3_bind_parameter_name $VM 4 ;# Ignore if index is too big
} {}
do_test bind-10.8 {
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 2 2
sqlite3_bind_int $VM 3 3
sqlite3_step $VM
} SQLITE_DONE
do_test bind-10.8.1 {
# Binding attempts after program start should fail
set rc [catch {
sqlite3_bind_int $VM 1 1
} msg]
lappend rc $msg
} {1 {}}
do_test bind-10.9 {
sqlite3_finalize $VM
} SQLITE_OK
do_test bind-10.10 {
execsql {SELECT * FROM t2}
} {1 999 1000 1001 {} {} 1 2 1 3 2 1}
# Ticket #918
#
do_test bind-10.11 {
# catch {sqlite3_finalize $VM}
set VM [
sqlite3_prepare $DB {
INSERT INTO t2(a,b,c,d,e,f) VALUES(:abc,?,?4,:pqr,:abc,?4)
} -1 TAIL
]
sqlite3_bind_parameter_count $VM
} 5
do_test bind-10.11.1 {
sqlite3_bind_parameter_index 0 :xyz ;# ignore NULL VM arguments
} 0
do_test bind-10.12 {
sqlite3_bind_parameter_index $VM :xyz
} 0
do_test bind-10.13 {
sqlite3_bind_parameter_index $VM {}
} 0
do_test bind-10.14 {
sqlite3_bind_parameter_index $VM :pqr
} 5
do_test bind-10.15 {
sqlite3_bind_parameter_index $VM ?4
} 4
do_test bind-10.16 {
sqlite3_bind_parameter_name $VM 1
} :abc
do_test bind-10.17 {
sqlite3_bind_parameter_name $VM 2
} {}
do_test bind-10.18 {
sqlite3_bind_parameter_name $VM 3
} {}
do_test bind-10.19 {
sqlite3_bind_parameter_name $VM 4
} {?4}
do_test bind-10.20 {
sqlite3_bind_parameter_name $VM 5
} :pqr
catch {sqlite3_finalize $VM}
# Make sure we catch an unterminated "(" in a Tcl-style variable name
#
ifcapable tclvar {
do_test bind-11.1 {
catchsql {SELECT * FROM sqlite_master WHERE name=$abc(123 and sql NOT NULL;}
} {1 {unrecognized token: "$abc(123"}}
}
if {[execsql {pragma encoding}]=="UTF-8"} {
# Test the ability to bind text that contains embedded '\000' characters.
# Make sure we can recover the entire input string.
#
do_test bind-12.1 {
execsql {
CREATE TABLE t3(x BLOB);
}
set VM [sqlite3_prepare $DB {INSERT INTO t3 VALUES(?)} -1 TAIL]
sqlite_bind $VM 1 not-used blob10
sqlite3_step $VM
sqlite3_finalize $VM
execsql {
SELECT typeof(x), length(x), quote(x),
length(cast(x AS BLOB)), quote(cast(x AS BLOB)) FROM t3
}
} {text 3 'abc' 10 X'6162630078797A007071'}
do_test bind-12.2 {
sqlite3_create_function $DB
execsql {
SELECT quote(cast(x_coalesce(x) AS blob)) FROM t3
}
} {X'6162630078797A007071'}
}
# Test the operation of sqlite3_clear_bindings
#
do_test bind-13.1 {
set VM [sqlite3_prepare $DB {SELECT ?,?,?} -1 TAIL]
sqlite3_step $VM
list [sqlite3_column_type $VM 0] [sqlite3_column_type $VM 1] \
[sqlite3_column_type $VM 2]
} {NULL NULL NULL}
do_test bind-13.2 {
sqlite3_reset $VM
sqlite3_bind_int $VM 1 1
sqlite3_bind_int $VM 2 2
sqlite3_bind_int $VM 3 3
sqlite3_step $VM
list [sqlite3_column_type $VM 0] [sqlite3_column_type $VM 1] \
[sqlite3_column_type $VM 2]
} {INTEGER INTEGER INTEGER}
do_test bind-13.3 {
sqlite3_reset $VM
sqlite3_step $VM
list [sqlite3_column_type $VM 0] [sqlite3_column_type $VM 1] \
[sqlite3_column_type $VM 2]
} {INTEGER INTEGER INTEGER}
do_test bind-13.4 {
sqlite3_reset $VM
sqlite3_clear_bindings $VM
sqlite3_step $VM
list [sqlite3_column_type $VM 0] [sqlite3_column_type $VM 1] \
[sqlite3_column_type $VM 2]
} {NULL NULL NULL}
sqlite3_finalize $VM
finish_test
+73
View File
@@ -0,0 +1,73 @@
# 2005 April 21
#
# 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 regression tests for SQLite library. The
# focus of this script testing the sqlite_transfer_bindings() API.
#
# $Id: bindxfer.test,v 1.2 2006/01/03 00:33:50 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
proc sqlite_step {stmt VALS COLS} {
upvar #0 $VALS vals
upvar #0 $COLS cols
set vals [list]
set cols [list]
set rc [sqlite3_step $stmt]
for {set i 0} {$i < [sqlite3_column_count $stmt]} {incr i} {
lappend cols [sqlite3_column_name $stmt $i]
}
for {set i 0} {$i < [sqlite3_data_count $stmt]} {incr i} {
lappend vals [sqlite3_column_text $stmt $i]
}
return $rc
}
do_test bindxfer-1.1 {
set DB [sqlite3_connection_pointer db]
execsql {CREATE TABLE t1(a,b,c);}
set VM1 [sqlite3_prepare $DB {SELECT ?, ?, ?} -1 TAIL]
set TAIL
} {}
do_test bindxfer-1.2 {
sqlite3_bind_parameter_count $VM1
} 3
do_test bindxfer-1.3 {
set VM2 [sqlite3_prepare $DB {SELECT ?, ?, ?} -1 TAIL]
set TAIL
} {}
do_test bindxfer-1.4 {
sqlite3_bind_parameter_count $VM2
} 3
do_test bindxfer-1.5 {
sqlite_bind $VM1 1 one normal
set sqlite_static_bind_value two
sqlite_bind $VM1 2 {} static
sqlite_bind $VM1 3 {} null
sqlite3_transfer_bindings $VM1 $VM2
sqlite_step $VM1 VALUES COLNAMES
} SQLITE_ROW
do_test bindxfer-1.6 {
set VALUES
} {{} {} {}}
do_test bindxfer-1.7 {
sqlite_step $VM2 VALUES COLNAMES
} SQLITE_ROW
do_test bindxfer-1.8 {
set VALUES
} {one two {}}
catch {sqlite3_finalize $VM1}
catch {sqlite3_finalize $VM2}
finish_test
+124
View File
@@ -0,0 +1,124 @@
# 2001 September 15
#
# 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 regression tests for SQLite library.
#
# $Id: blob.test,v 1.5 2006/01/03 00:33:50 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!bloblit} {
finish_test
return
}
proc bin_to_hex {blob} {
set bytes {}
binary scan $blob \c* bytes
set bytes2 [list]
foreach b $bytes {lappend bytes2 [format %02X [expr $b & 0xFF]]}
join $bytes2 {}
}
# Simplest possible case. Specify a blob literal
do_test blob-1.0 {
set blob [execsql {SELECT X'01020304';}]
bin_to_hex [lindex $blob 0]
} {01020304}
do_test blob-1.1 {
set blob [execsql {SELECT x'ABCDEF';}]
bin_to_hex [lindex $blob 0]
} {ABCDEF}
do_test blob-1.2 {
set blob [execsql {SELECT x'';}]
bin_to_hex [lindex $blob 0]
} {}
do_test blob-1.3 {
set blob [execsql {SELECT x'abcdEF12';}]
bin_to_hex [lindex $blob 0]
} {ABCDEF12}
# Try some syntax errors in blob literals.
do_test blob-1.4 {
catchsql {SELECT X'01020k304', 100}
} {1 {unrecognized token: "X'01020"}}
do_test blob-1.5 {
catchsql {SELECT X'01020, 100}
} {1 {unrecognized token: "X'01020"}}
do_test blob-1.6 {
catchsql {SELECT X'01020 100'}
} {1 {unrecognized token: "X'01020"}}
do_test blob-1.7 {
catchsql {SELECT X'01001'}
} {1 {unrecognized token: "X'01001'"}}
# Insert a blob into a table and retrieve it.
do_test blob-2.0 {
execsql {
CREATE TABLE t1(a BLOB, b BLOB);
INSERT INTO t1 VALUES(X'123456', x'7890ab');
INSERT INTO t1 VALUES(X'CDEF12', x'345678');
}
set blobs [execsql {SELECT * FROM t1}]
set blobs2 [list]
foreach b $blobs {lappend blobs2 [bin_to_hex $b]}
set blobs2
} {123456 7890AB CDEF12 345678}
# An index on a blob column
do_test blob-2.1 {
execsql {
CREATE INDEX i1 ON t1(a);
}
set blobs [execsql {SELECT * FROM t1}]
set blobs2 [list]
foreach b $blobs {lappend blobs2 [bin_to_hex $b]}
set blobs2
} {123456 7890AB CDEF12 345678}
do_test blob-2.2 {
set blobs [execsql {SELECT * FROM t1 where a = X'123456'}]
set blobs2 [list]
foreach b $blobs {lappend blobs2 [bin_to_hex $b]}
set blobs2
} {123456 7890AB}
do_test blob-2.3 {
set blobs [execsql {SELECT * FROM t1 where a = X'CDEF12'}]
set blobs2 [list]
foreach b $blobs {lappend blobs2 [bin_to_hex $b]}
set blobs2
} {CDEF12 345678}
do_test blob-2.4 {
set blobs [execsql {SELECT * FROM t1 where a = X'CD12'}]
set blobs2 [list]
foreach b $blobs {lappend blobs2 [bin_to_hex $b]}
set blobs2
} {}
# Try to bind a blob value to a prepared statement.
do_test blob-3.0 {
sqlite3 db2 test.db
set DB [sqlite3_connection_pointer db2]
set STMT [sqlite3_prepare $DB "DELETE FROM t1 WHERE a = ?" -1 DUMMY]
sqlite3_bind_blob $STMT 1 "\x12\x34\x56" 3
sqlite3_step $STMT
} {SQLITE_DONE}
do_test blob-3.1 {
sqlite3_finalize $STMT
db2 close
} {}
do_test blob-2.3 {
set blobs [execsql {SELECT * FROM t1}]
set blobs2 [list]
foreach b $blobs {lappend blobs2 [bin_to_hex $b]}
set blobs2
} {CDEF12 345678}
finish_test
File diff suppressed because it is too large Load Diff
+502
View File
@@ -0,0 +1,502 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is btree database backend
#
# $Id: btree2.test,v 1.15 2006/03/19 13:00:25 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {[info commands btree_open]!=""} {
# Create a new database file containing no entries. The database should
# contain 5 tables:
#
# 2 The descriptor table
# 3 The foreground table
# 4 The background table
# 5 The long key table
# 6 The long data table
#
# An explanation for what all these tables are used for is provided below.
#
do_test btree2-1.1 {
expr srand(1)
file delete -force test2.bt
file delete -force test2.bt-journal
set ::b [btree_open test2.bt 2000 0]
btree_begin_transaction $::b
btree_create_table $::b 0
} {2}
do_test btree2-1.2 {
btree_create_table $::b 0
} {3}
do_test btree2-1.3 {
btree_create_table $::b 0
} {4}
do_test btree2-1.4 {
btree_create_table $::b 0
} {5}
do_test btree2-1.5 {
btree_create_table $::b 0
} {6}
do_test btree2-1.6 {
set ::c2 [btree_cursor $::b 2 1]
btree_insert $::c2 {one} {1}
btree_move_to $::c2 {one}
btree_delete $::c2
btree_close_cursor $::c2
btree_commit $::b
btree_integrity_check $::b 1 2 3 4 5 6
} {}
# This test module works by making lots of pseudo-random changes to a
# database while simultaneously maintaining an invariant on that database.
# Periodically, the script does a sanity check on the database and verifies
# that the invariant is satisfied.
#
# The invariant is as follows:
#
# 1. The descriptor table always contains 2 enters. An entry keyed by
# "N" is the number of elements in the foreground and background tables
# combined. The entry keyed by "L" is the number of digits in the keys
# for foreground and background tables.
#
# 2. The union of the foreground an background tables consists of N entries
# where each entry has an L-digit key. (Actually, some keys can be longer
# than L characters, but they always start with L digits.) The keys
# cover all integers between 1 and N. Whenever an entry is added to
# the foreground it is removed form the background and vice versa.
#
# 3. Some entries in the foreground and background tables have keys that
# begin with an L-digit number but are followed by additional characters.
# For each such entry there is a corresponding entry in the long key
# table. The long key table entry has a key which is just the L-digit
# number and data which is the length of the key in the foreground and
# background tables.
#
# 4. The data for both foreground and background entries is usually a
# short string. But some entries have long data strings. For each
# such entries there is an entry in the long data type. The key to
# long data table is an L-digit number. (The extension on long keys
# is omitted.) The data is the number of charaters in the data of the
# foreground or background entry.
#
# The following function builds a database that satisfies all of the above
# invariants.
#
proc build_db {N L} {
for {set i 2} {$i<=6} {incr i} {
catch {btree_close_cursor [set ::c$i]}
btree_clear_table $::b $i
set ::c$i [btree_cursor $::b $i 1]
}
btree_insert $::c2 N $N
btree_insert $::c2 L $L
set format %0${L}d
for {set i 1} {$i<=$N} {incr i} {
set key [format $format $i]
set data $key
btree_insert $::c3 $key $data
}
}
# Given a base key number and a length, construct the full text of the key
# or data.
#
proc make_payload {keynum L len} {
set key [format %0${L}d $keynum]
set r $key
set i 1
while {[string length $r]<$len} {
append r " ($i) $key"
incr i
}
return [string range $r 0 [expr {$len-1}]]
}
# Verify the invariants on the database. Return an empty string on
# success or an error message if something is amiss.
#
proc check_invariants {} {
set ck [btree_integrity_check $::b 1 2 3 4 5 6]
if {$ck!=""} {
puts "\n*** SANITY:\n$ck"
exit
return $ck
}
btree_move_to $::c3 {}
btree_move_to $::c4 {}
btree_move_to $::c2 N
set N [btree_data $::c2]
btree_move_to $::c2 L
set L [btree_data $::c2]
set LM1 [expr {$L-1}]
for {set i 1} {$i<=$N} {incr i} {
set key {}
if {![btree_eof $::c3]} {
set key [btree_key $::c3]
}
if {[scan $key %d k]<1} {set k 0}
if {$k!=$i} {
set key {}
if {![btree_eof $::c4]} {
set key [btree_key $::c4]
}
if {[scan $key %d k]<1} {set k 0}
if {$k!=$i} {
return "Key $i is missing from both foreground and background"
}
set data [btree_data $::c4]
btree_next $::c4
} else {
set data [btree_data $::c3]
btree_next $::c3
}
set skey [string range $key 0 $LM1]
if {[btree_move_to $::c5 $skey]==0} {
set keylen [btree_data $::c5]
} else {
set keylen $L
}
if {[string length $key]!=$keylen} {
return "Key $i is the wrong size.\
Is \"$key\" but should be \"[make_payload $k $L $keylen]\""
}
if {[make_payload $k $L $keylen]!=$key} {
return "Key $i has an invalid extension"
}
if {[btree_move_to $::c6 $skey]==0} {
set datalen [btree_data $::c6]
} else {
set datalen $L
}
if {[string length $data]!=$datalen} {
return "Data for $i is the wrong size.\
Is [string length $data] but should be $datalen"
}
if {[make_payload $k $L $datalen]!=$data} {
return "Entry $i has an incorrect data"
}
}
}
# Look at all elements in both the foreground and background tables.
# Make sure the key is always the same as the prefix of the data.
#
# This routine was used for hunting bugs. It is not a part of standard
# tests.
#
proc check_data {n key} {
global c3 c4
incr n -1
foreach c [list $c3 $c4] {
btree_first $c ;# move_to $c $key
set cnt 0
while {![btree_eof $c]} {
set key [btree_key $c]
set data [btree_data $c]
if {[string range $key 0 $n] ne [string range $data 0 $n]} {
puts "key=[list $key] data=[list $data] n=$n"
puts "cursor info = [btree_cursor_info $c]"
btree_page_dump $::b [lindex [btree_cursor_info $c] 0]
exit
}
btree_next $c
}
}
}
# Make random changes to the database such that each change preserves
# the invariants. The number of changes is $n*N where N is the parameter
# from the descriptor table. Each changes begins with a random key.
# the entry with that key is put in the foreground table with probability
# $I and it is put in background with probability (1.0-$I). It gets
# a long key with probability $K and long data with probability $D.
#
set chngcnt 0
proc random_changes {n I K D} {
global chngcnt
btree_move_to $::c2 N
set N [btree_data $::c2]
btree_move_to $::c2 L
set L [btree_data $::c2]
set LM1 [expr {$L-1}]
set total [expr {int($N*$n)}]
set format %0${L}d
for {set i 0} {$i<$total} {incr i} {
set k [expr {int(rand()*$N)+1}]
set insert [expr {rand()<=$I}]
set longkey [expr {rand()<=$K}]
set longdata [expr {rand()<=$D}]
if {$longkey} {
set x [expr {rand()}]
set keylen [expr {int($x*$x*$x*$x*3000)+10}]
} else {
set keylen $L
}
set key [make_payload $k $L $keylen]
if {$longdata} {
set x [expr {rand()}]
set datalen [expr {int($x*$x*$x*$x*3000)+10}]
} else {
set datalen $L
}
set data [make_payload $k $L $datalen]
set basekey [format $format $k]
if {[set c [btree_move_to $::c3 $basekey]]==0} {
btree_delete $::c3
} else {
if {$c<0} {btree_next $::c3}
if {![btree_eof $::c3]} {
if {[string match $basekey* [btree_key $::c3]]} {
btree_delete $::c3
}
}
}
if {[set c [btree_move_to $::c4 $basekey]]==0} {
btree_delete $::c4
} else {
if {$c<0} {btree_next $::c4}
if {![btree_eof $::c4]} {
if {[string match $basekey* [btree_key $::c4]]} {
btree_delete $::c4
}
}
}
set kx -1
if {![btree_eof $::c4]} {
if {[scan [btree_key $::c4] %d kx]<1} {set kx -1}
}
if {$kx==$k} {
btree_delete $::c4
}
# For debugging - change the "0" to "1" to integrity check after
# every change.
if 0 {
incr chngcnt
puts check----$chngcnt
set ck [btree_integrity_check $::b 1 2 3 4 5 6]
if {$ck!=""} {
puts "\nSANITY CHECK FAILED!\n$ck"
exit
}
}
if {$insert} {
btree_insert $::c3 $key $data
} else {
btree_insert $::c4 $key $data
}
if {$longkey} {
btree_insert $::c5 $basekey $keylen
} elseif {[btree_move_to $::c5 $basekey]==0} {
btree_delete $::c5
}
if {$longdata} {
btree_insert $::c6 $basekey $datalen
} elseif {[btree_move_to $::c6 $basekey]==0} {
btree_delete $::c6
}
# For debugging - change the "0" to "1" to integrity check after
# every change.
if 0 {
incr chngcnt
puts check----$chngcnt
set ck [btree_integrity_check $::b 1 2 3 4 5 6]
if {$ck!=""} {
puts "\nSANITY CHECK FAILED!\n$ck"
exit
}
}
}
}
set btree_trace 0
# Repeat this test sequence on database of various sizes
#
set testno 2
foreach {N L} {
10 2
50 2
200 3
2000 5
} {
puts "**** N=$N L=$L ****"
set hash [md5file test2.bt]
do_test btree2-$testno.1 [subst -nocommands {
set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6 1]
btree_begin_transaction $::b
build_db $N $L
check_invariants
}] {}
do_test btree2-$testno.2 {
btree_close_cursor $::c2
btree_close_cursor $::c3
btree_close_cursor $::c4
btree_close_cursor $::c5
btree_close_cursor $::c6
btree_rollback $::b
md5file test2.bt
} $hash
do_test btree2-$testno.3 [subst -nocommands {
btree_begin_transaction $::b
set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6 1]
build_db $N $L
check_invariants
}] {}
do_test btree2-$testno.4 {
btree_commit $::b
check_invariants
} {}
do_test btree2-$testno.5 {
lindex [btree_pager_stats $::b] 1
} {6}
do_test btree2-$testno.6 {
btree_cursor_info $::c2
btree_cursor_info $::c3
btree_cursor_info $::c4
btree_cursor_info $::c5
btree_cursor_info $::c6
btree_close_cursor $::c2
btree_close_cursor $::c3
btree_close_cursor $::c4
btree_close_cursor $::c5
btree_close_cursor $::c6
lindex [btree_pager_stats $::b] 1
} {0}
do_test btree2-$testno.7 {
btree_close $::b
} {}
# For each database size, run various changes tests.
#
set num2 1
foreach {n I K D} {
0.5 0.5 0.1 0.1
1.0 0.2 0.1 0.1
1.0 0.8 0.1 0.1
2.0 0.0 0.1 0.1
2.0 1.0 0.1 0.1
2.0 0.0 0.0 0.0
2.0 1.0 0.0 0.0
} {
set testid btree2-$testno.8.$num2
set hash [md5file test2.bt]
do_test $testid.0 {
set ::b [btree_open test2.bt 2000 0]
set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6 1]
check_invariants
} {}
set cnt 6
for {set i 2} {$i<=6} {incr i} {
if {[lindex [btree_cursor_info [set ::c$i]] 0]!=$i} {incr cnt}
}
do_test $testid.1 {
btree_begin_transaction $::b
lindex [btree_pager_stats $::b] 1
} $cnt
do_test $testid.2 [subst {
random_changes $n $I $K $D
}] {}
do_test $testid.3 {
check_invariants
} {}
do_test $testid.4 {
btree_close_cursor $::c2
btree_close_cursor $::c3
btree_close_cursor $::c4
btree_close_cursor $::c5
btree_close_cursor $::c6
btree_rollback $::b
md5file test2.bt
} $hash
btree_begin_transaction $::b
set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6 1]
do_test $testid.5 [subst {
random_changes $n $I $K $D
}] {}
do_test $testid.6 {
check_invariants
} {}
do_test $testid.7 {
btree_commit $::b
check_invariants
} {}
set hash [md5file test2.bt]
do_test $testid.8 {
btree_close_cursor $::c2
btree_close_cursor $::c3
btree_close_cursor $::c4
btree_close_cursor $::c5
btree_close_cursor $::c6
lindex [btree_pager_stats $::b] 1
} {0}
do_test $testid.9 {
btree_close $::b
set ::b [btree_open test2.bt 2000 0]
set ::c2 [btree_cursor $::b 2 1]
set ::c3 [btree_cursor $::b 3 1]
set ::c4 [btree_cursor $::b 4 1]
set ::c5 [btree_cursor $::b 5 1]
set ::c6 [btree_cursor $::b 6 1]
check_invariants
} {}
do_test $testid.10 {
btree_close_cursor $::c2
btree_close_cursor $::c3
btree_close_cursor $::c4
btree_close_cursor $::c5
btree_close_cursor $::c6
lindex [btree_pager_stats $::b] 1
} {0}
do_test $testid.11 {
btree_close $::b
} {}
incr num2
}
incr testno
set ::b [btree_open test2.bt 2000 0]
}
# Testing is complete. Shut everything down.
#
do_test btree-999.1 {
lindex [btree_pager_stats $::b] 1
} {0}
do_test btree-999.2 {
btree_close $::b
} {}
do_test btree-999.3 {
file delete -force test2.bt
file exists test2.bt-journal
} {0}
} ;# end if( not mem: and has pager_open command );
finish_test
+101
View File
@@ -0,0 +1,101 @@
# 2002 December 03
#
# 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 regression tests for SQLite library. The
# focus of this script is btree database backend
#
# This file focuses on testing the sqliteBtreeNext() and
# sqliteBtreePrevious() procedures and making sure they are able
# to step through an entire table from either direction.
#
# $Id: btree4.test,v 1.2 2004/05/09 20:40:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {[info commands btree_open]!=""} {
# Open a test database.
#
file delete -force test1.bt
file delete -force test1.bt-journal
set b1 [btree_open test1.bt 2000 0]
btree_begin_transaction $b1
do_test btree4-0.1 {
btree_create_table $b1 0
} 2
set data {abcdefghijklmnopqrstuvwxyz0123456789}
append data $data
append data $data
append data $data
append data $data
foreach N {10 100 1000} {
btree_clear_table $::b1 2
set ::c1 [btree_cursor $::b1 2 1]
do_test btree4-$N.1 {
for {set i 1} {$i<=$N} {incr i} {
btree_insert $::c1 [format k-%05d $i] $::data-$i
}
btree_first $::c1
btree_key $::c1
} {k-00001}
do_test btree4-$N.2 {
btree_data $::c1
} $::data-1
for {set i 2} {$i<=$N} {incr i} {
do_test btree-$N.3.$i.1 {
btree_next $::c1
} 0
do_test btree-$N.3.$i.2 {
btree_key $::c1
} [format k-%05d $i]
do_test btree-$N.3.$i.3 {
btree_data $::c1
} $::data-$i
}
do_test btree4-$N.4 {
btree_next $::c1
} 1
do_test btree4-$N.5 {
btree_last $::c1
} 0
do_test btree4-$N.6 {
btree_key $::c1
} [format k-%05d $N]
do_test btree4-$N.7 {
btree_data $::c1
} $::data-$N
for {set i [expr {$N-1}]} {$i>=1} {incr i -1} {
do_test btree4-$N.8.$i.1 {
btree_prev $::c1
} 0
do_test btree4-$N.8.$i.2 {
btree_key $::c1
} [format k-%05d $i]
do_test btree4-$N.8.$i.3 {
btree_data $::c1
} $::data-$i
}
do_test btree4-$N.9 {
btree_prev $::c1
} 1
btree_close_cursor $::c1
}
btree_rollback $::b1
btree_pager_ref_dump $::b1
btree_close $::b1
} ;# end if( not mem: and has pager_open command );
finish_test
+292
View File
@@ -0,0 +1,292 @@
# 2004 May 10
#
# 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 regression tests for SQLite library. The
# focus of this script is btree database backend
#
# $Id: btree5.test,v 1.5 2004/05/14 12:17:46 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Attempting to read table 1 of an empty file gives an SQLITE_EMPTY
# error.
#
do_test btree5-1.1 {
file delete -force test1.bt
file delete -force test1.bt-journal
set rc [catch {btree_open test1.bt 2000 0} ::b1]
} {0}
do_test btree5-1.2 {
set rc [catch {btree_cursor $::b1 1 0} ::c1]
} {1}
do_test btree5-1.3 {
set ::c1
} {SQLITE_EMPTY}
do_test btree5-1.4 {
set rc [catch {btree_cursor $::b1 1 1} ::c1]
} {1}
do_test btree5-1.5 {
set ::c1
} {SQLITE_EMPTY}
# Starting a transaction initializes the first page of the database
# and the error goes away.
#
do_test btree5-1.6 {
btree_begin_transaction $b1
set rc [catch {btree_cursor $b1 1 0} c1]
} {0}
do_test btree5-1.7 {
btree_first $c1
} {1}
do_test btree5-1.8 {
btree_close_cursor $c1
btree_rollback $b1
set rc [catch {btree_cursor $b1 1 0} c1]
} {1}
do_test btree5-1.9 {
set c1
} {SQLITE_EMPTY}
do_test btree5-1.10 {
btree_begin_transaction $b1
set rc [catch {btree_cursor $b1 1 0} c1]
} {0}
do_test btree5-1.11 {
btree_first $c1
} {1}
do_test btree5-1.12 {
btree_close_cursor $c1
btree_commit $b1
set rc [catch {btree_cursor $b1 1 0} c1]
} {0}
do_test btree5-1.13 {
btree_first $c1
} {1}
do_test btree5-1.14 {
btree_close_cursor $c1
btree_integrity_check $b1 1
} {}
# Insert many entries into table 1. This is designed to test the
# virtual-root logic that comes into play for page one. It is also
# a good test of INTKEY tables.
#
# Stagger the inserts. After the inserts complete, go back and do
# deletes. Stagger the deletes too. Repeat this several times.
#
# Do N inserts into table 1 using random keys between 0 and 1000000
#
proc random_inserts {N} {
global c1
while {$N>0} {
set k [expr {int(rand()*1000000)}]
if {[btree_move_to $c1 $k]==0} continue; # entry already exists
btree_insert $c1 $k data-for-$k
incr N -1
}
}
# Do N delete from table 1
#
proc random_deletes {N} {
global c1
while {$N>0} {
set k [expr {int(rand()*1000000)}]
btree_move_to $c1 $k
btree_delete $c1
incr N -1
}
}
# Make sure the table has exactly N entries. Make sure the data for
# each entry agrees with its key.
#
proc check_table {N} {
global c1
btree_first $c1
set cnt 0
while {![btree_eof $c1]} {
if {[set data [btree_data $c1]] ne "data-for-[btree_key $c1]"} {
return "wrong data for entry $cnt"
}
set n [string length $data]
set fdata1 [btree_fetch_data $c1 $n]
set fdata2 [btree_fetch_data $c1 -1]
if {$fdata1 ne "" && $fdata1 ne $data} {
return "DataFetch returned the wrong value with amt=$n"
}
if {$fdata1 ne $fdata2} {
return "DataFetch returned the wrong value when amt=-1"
}
if {$n>10} {
set fdata3 [btree_fetch_data $c1 10]
if {$fdata3 ne [string range $data 0 9]} {
return "DataFetch returned the wrong value when amt=10"
}
}
incr cnt
btree_next $c1
}
if {$cnt!=$N} {
return "wrong number of entries"
}
return {}
}
# Initialize the database
#
btree_begin_transaction $b1
set c1 [btree_cursor $b1 1 1]
set btree_trace 0
# Do the tests.
#
set cnt 0
for {set i 1} {$i<=100} {incr i} {
do_test btree5-2.$i.1 {
random_inserts 200
incr cnt 200
check_table $cnt
} {}
do_test btree5-2.$i.2 {
btree_integrity_check $b1 1
} {}
do_test btree5-2.$i.3 {
random_deletes 190
incr cnt -190
check_table $cnt
} {}
do_test btree5-2.$i.4 {
btree_integrity_check $b1 1
} {}
}
#btree_tree_dump $b1 1
btree_close_cursor $c1
btree_commit $b1
btree_begin_transaction $b1
# This procedure converts an integer into a variable-length text key.
# The conversion is reversible.
#
# The first two characters of the string are alphabetics derived from
# the least significant bits of the number. Because they are derived
# from least significant bits, the sort order of the resulting string
# is different from numeric order. After the alphabetic prefix comes
# the original number. A variable-length suffix follows. The length
# of the suffix is based on a hash of the original number.
#
proc num_to_key {n} {
global charset ncharset suffix
set c1 [string index $charset [expr {$n%$ncharset}]]
set c2 [string index $charset [expr {($n/$ncharset)%$ncharset}]]
set nsuf [expr {($n*211)%593}]
return $c1$c2-$n-[string range $suffix 0 $nsuf]
}
set charset {abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ}
set ncharset [string length $charset]
set suffix $charset$charset
while {[string length $suffix]<1000} {append suffix $suffix}
# This procedures extracts the original integer used to create
# a key by num_to_key
#
proc key_to_num {key} {
regexp {^..-([0-9]+)} $key all n
return $n
}
# Insert into table $tab keys corresponding to all values between
# $start and $end, inclusive.
#
proc insert_range {tab start end} {
for {set i $start} {$i<=$end} {incr i} {
btree_insert $tab [num_to_key $i] {}
}
}
# Delete from table $tab keys corresponding to all values between
# $start and $end, inclusive.
#
proc delete_range {tab start end} {
for {set i $start} {$i<=$end} {incr i} {
if {[btree_move_to $tab [num_to_key $i]]==0} {
btree_delete $tab
}
}
}
# Make sure table $tab contains exactly those keys corresponding
# to values between $start and $end
#
proc check_range {tab start end} {
btree_first $tab
while {![btree_eof $tab]} {
set key [btree_key $tab]
set i [key_to_num $key]
if {[num_to_key $i] ne $key} {
return "malformed key: $key"
}
set got($i) 1
btree_next $tab
}
set all [lsort -integer [array names got]]
if {[llength $all]!=$end+1-$start} {
return "table contains wrong number of values"
}
if {[lindex $all 0]!=$start} {
return "wrong starting value"
}
if {[lindex $all end]!=$end} {
return "wrong ending value"
}
return {}
}
# Create a zero-data table and test it out.
#
do_test btree5-3.1 {
set rc [catch {btree_create_table $b1 2} t2]
} {0}
do_test btree5-3.2 {
set rc [catch {btree_cursor $b1 $t2 1} c2]
} {0}
set start 1
set end 100
for {set i 1} {$i<=100} {incr i} {
do_test btree5-3.3.$i.1 {
insert_range $c2 $start $end
btree_integrity_check $b1 1 $t2
} {}
do_test btree5-3.3.$i.2 {
check_range $c2 $start $end
} {}
set nstart $start
incr nstart 89
do_test btree5-3.3.$i.3 {
delete_range $c2 $start $nstart
btree_integrity_check $b1 1 $t2
} {}
incr start 90
do_test btree5-3.3.$i.4 {
check_range $c2 $start $end
} {}
incr end 100
}
btree_close_cursor $c2
btree_commit $b1
btree_close $b1
finish_test
+128
View File
@@ -0,0 +1,128 @@
# 2004 May 10
#
# 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 regression tests for SQLite library. The
# focus of this script is btree database backend - specifically
# the B+tree tables. B+trees store all data on the leaves rather
# that storing data with keys on interior nodes.
#
# $Id: btree6.test,v 1.4 2004/05/20 22:16:31 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Insert many entries into the table that cursor $cur points to.
# The table should be an INTKEY table.
#
# Stagger the inserts. After the inserts complete, go back and do
# deletes. Stagger the deletes too. Repeat this several times.
#
# Do N inserts into table $tab using random keys between 0 and 1000000
#
proc random_inserts {cur N} {
global inscnt
while {$N>0} {
set k [expr {int(rand()*1000000)}]
if {[btree_move_to $cur $k]==0} {
continue; # entry already exists
}
incr inscnt
btree_insert $cur $k data-for-$k
incr N -1
}
}
set inscnt 0
# Do N delete from the table that $cur points to.
#
proc random_deletes {cur N} {
while {$N>0} {
set k [expr {int(rand()*1000000)}]
btree_move_to $cur $k
btree_delete $cur
incr N -1
}
}
# Make sure the table that $cur points to has exactly N entries.
# Make sure the data for each entry agrees with its key.
#
proc check_table {cur N} {
btree_first $cur
set cnt 0
while {![btree_eof $cur]} {
if {[set data [btree_data $cur]] ne "data-for-[btree_key $cur]"} {
return "wrong data for entry $cnt"
}
set n [string length $data]
set fdata1 [btree_fetch_data $cur $n]
set fdata2 [btree_fetch_data $cur -1]
if {$fdata1 ne "" && $fdata1 ne $data} {
return "DataFetch returned the wrong value with amt=$n"
}
if {$fdata1 ne $fdata2} {
return "DataFetch returned the wrong value when amt=-1"
}
if {$n>10} {
set fdata3 [btree_fetch_data $cur 10]
if {$fdata3 ne [string range $data 0 9]} {
return "DataFetch returned the wrong value when amt=10"
}
}
incr cnt
btree_next $cur
}
if {$cnt!=$N} {
return "wrong number of entries. Got $cnt. Looking for $N"
}
return {}
}
# Initialize the database
#
file delete -force test1.bt
file delete -force test1.bt-journal
set b1 [btree_open test1.bt 2000 0]
btree_begin_transaction $b1
set tab [btree_create_table $b1 5]
set cur [btree_cursor $b1 $tab 1]
set btree_trace 0
expr srand(1)
# Do the tests.
#
set cnt 0
for {set i 1} {$i<=40} {incr i} {
do_test btree6-1.$i.1 {
random_inserts $cur 200
incr cnt 200
check_table $cur $cnt
} {}
do_test btree6-1.$i.2 {
btree_integrity_check $b1 1 $tab
} {}
do_test btree6-1.$i.3 {
random_deletes $cur 90
incr cnt -90
check_table $cur $cnt
} {}
do_test btree6-1.$i.4 {
btree_integrity_check $b1 1 $tab
} {}
}
btree_close_cursor $cur
btree_commit $b1
btree_close $b1
finish_test
+50
View File
@@ -0,0 +1,50 @@
# 2004 Jun 4
#
# 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 regression tests for SQLite library. The
# focus of this script is btree database backend.
#
# $Id: btree7.test,v 1.2 2004/11/04 14:47:13 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Stress the balance routine by trying to create situations where
# 3 neighboring nodes split into 5.
#
set bigdata _123456789 ;# 10
append bigdata $bigdata ;# 20
append bigdata $bigdata ;# 40
append bigdata $bigdata ;# 80
append bigdata $bigdata ;# 160
append bigdata $bigdata ;# 320
append bigdata $bigdata ;# 640
set data450 [string range $bigdata 0 449]
do_test btree7-1.1 {
execsql "
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
INSERT INTO t1 VALUES(1, '$bigdata');
INSERT INTO t1 VALUES(2, '$bigdata');
INSERT INTO t1 VALUES(3, '$data450');
INSERT INTO t1 VALUES(5, '$data450');
INSERT INTO t1 VALUES(8, '$bigdata');
INSERT INTO t1 VALUES(9, '$bigdata');
"
} {}
integrity_check btree7-1.2
do_test btree7-1.3 {
execsql "
INSERT INTO t1 VALUES(4, '$bigdata');
"
} {}
integrity_check btree7-1.4
finish_test
+43
View File
@@ -0,0 +1,43 @@
# 2005 August 2
#
# 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 regression tests for SQLite library. The
# focus of this script is btree database backend.
#
# $Id: btree8.test,v 1.6 2005/08/02 17:13:12 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Ticket #1346: If the table rooted on page 1 contains a single entry
# and that single entries has to flow out into another page because
# page 1 is 100-bytes smaller than most other pages, then you delete that
# one entry, everything should still work.
#
do_test btree8-1.1 {
execsql {
CREATE TABLE t1(x
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
);
DROP table t1;
}
} {}
integrity_check btree8-1.2
+44
View File
@@ -0,0 +1,44 @@
# 2005 july 8
#
# 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 test the busy handler
#
# $Id: busy.test,v 1.2 2005/09/17 18:02:37 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test busy-1.1 {
sqlite3 db2 test.db
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
SELECT * FROM t1
}
} 1
proc busy x {
lappend ::busyargs $x
if {$x>2} {return 1}
return 0
}
set busyargs {}
do_test busy-1.2 {
db busy busy
db2 eval {begin exclusive}
catchsql {begin immediate}
} {1 {database is locked}}
do_test busy-1.3 {
set busyargs
} {0 1 2 3}
db2 close
finish_test
+793
View File
@@ -0,0 +1,793 @@
# 2003 January 29
#
# 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 regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi2.test,v 1.32 2006/08/16 16:42:48 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Return the text values from the current row pointed at by STMT as a list.
proc get_row_values {STMT} {
set VALUES [list]
for {set i 0} {$i < [sqlite3_data_count $STMT]} {incr i} {
lappend VALUES [sqlite3_column_text $STMT $i]
}
return $VALUES
}
# Return the column names followed by declaration types for the result set
# of the SQL statement STMT.
#
# i.e. for:
# CREATE TABLE abc(a text, b integer);
# SELECT * FROM abc;
#
# The result is {a b text integer}
proc get_column_names {STMT} {
set VALUES [list]
for {set i 0} {$i < [sqlite3_column_count $STMT]} {incr i} {
lappend VALUES [sqlite3_column_name $STMT $i]
}
for {set i 0} {$i < [sqlite3_column_count $STMT]} {incr i} {
lappend VALUES [sqlite3_column_decltype $STMT $i]
}
return $VALUES
}
# Check basic functionality
#
do_test capi2-1.1 {
set DB [sqlite3_connection_pointer db]
execsql {CREATE TABLE t1(a,b,c)}
set VM [sqlite3_prepare $DB {SELECT name, rowid FROM sqlite_master} -1 TAIL]
set TAIL
} {}
do_test capi2-1.2 {
sqlite3_step $VM
} {SQLITE_ROW}
do_test capi2-1.3 {
sqlite3_data_count $VM
} {2}
do_test capi2-1.4 {
get_row_values $VM
} {t1 1}
do_test capi2-1.5 {
get_column_names $VM
} {name rowid text INTEGER}
do_test capi2-1.6 {
sqlite3_step $VM
} {SQLITE_DONE}
do_test capi2-1.7 {
list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM]
} {2 {} {name rowid text INTEGER}}
do_test capi2-1.8 {
sqlite3_step $VM
} {SQLITE_MISUSE}
# Update: In v2, once SQLITE_MISUSE is returned the statement handle cannot
# be interrogated for more information. However in v3, since the column
# count, names and types are determined at compile time, these are still
# accessible after an SQLITE_MISUSE error.
do_test capi2-1.9 {
list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM]
} {2 {} {name rowid text INTEGER}}
do_test capi2-1.10 {
sqlite3_data_count $VM
} {0}
do_test capi2-1.11 {
sqlite3_finalize $VM
} {SQLITE_OK}
# Check to make sure that the "tail" of a multi-statement SQL script
# is returned by sqlite3_prepare.
#
do_test capi2-2.1 {
set SQL {
SELECT name, rowid FROM sqlite_master;
SELECT name, rowid FROM sqlite_master WHERE 0;
-- A comment at the end
}
set VM [sqlite3_prepare $DB $SQL -1 SQL]
set SQL
} {
SELECT name, rowid FROM sqlite_master WHERE 0;
-- A comment at the end
}
do_test capi2-2.2 {
set r [sqlite3_step $VM]
lappend r [sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_ROW 2 {t1 1} {name rowid text INTEGER}}
do_test capi2-2.3 {
set r [sqlite3_step $VM]
lappend r [sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_DONE 2 {} {name rowid text INTEGER}}
do_test capi2-2.4 {
sqlite3_finalize $VM
} {SQLITE_OK}
do_test capi2-2.5 {
set VM [sqlite3_prepare $DB $SQL -1 SQL]
set SQL
} {
-- A comment at the end
}
do_test capi2-2.6 {
set r [sqlite3_step $VM]
lappend r [sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_DONE 2 {} {name rowid text INTEGER}}
do_test capi2-2.7 {
sqlite3_finalize $VM
} {SQLITE_OK}
do_test capi2-2.8 {
set VM [sqlite3_prepare $DB $SQL -1 SQL]
list $SQL $VM
} {{} {}}
# Check the error handling.
#
do_test capi2-3.1 {
set rc [catch {
sqlite3_prepare $DB {select bogus from sqlite_master} -1 TAIL
} msg]
lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {}}
do_test capi2-3.2 {
set rc [catch {
sqlite3_prepare $DB {select bogus from } -1 TAIL
} msg]
lappend rc $msg $TAIL
} {1 {(1) near " ": syntax error} {}}
do_test capi2-3.3 {
set rc [catch {
sqlite3_prepare $DB {;;;;select bogus from sqlite_master} -1 TAIL
} msg]
lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {}}
do_test capi2-3.4 {
set rc [catch {
sqlite3_prepare $DB {select bogus from sqlite_master;x;} -1 TAIL
} msg]
lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {x;}}
do_test capi2-3.5 {
set rc [catch {
sqlite3_prepare $DB {select bogus from sqlite_master;;;x;} -1 TAIL
} msg]
lappend rc $msg $TAIL
} {1 {(1) no such column: bogus} {;;x;}}
do_test capi2-3.6 {
set rc [catch {
sqlite3_prepare $DB {select 5/0} -1 TAIL
} VM]
lappend rc $TAIL
} {0 {}}
do_test capi2-3.7 {
list [sqlite3_step $VM] \
[sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_ROW 1 {{}} {5/0 {}}}
do_test capi2-3.8 {
sqlite3_finalize $VM
} {SQLITE_OK}
do_test capi2-3.9 {
execsql {CREATE UNIQUE INDEX i1 ON t1(a)}
set VM [sqlite3_prepare $DB {INSERT INTO t1 VALUES(1,2,3)} -1 TAIL]
set TAIL
} {}
do_test capi2-3.9b {db changes} {0}
do_test capi2-3.10 {
list [sqlite3_step $VM] \
[sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_DONE 0 {} {}}
# Update for v3 - the change has not actually happened until the query is
# finalized. Is this going to cause trouble for anyone? Lee Nelson maybe?
# (Later:) The change now happens just before SQLITE_DONE is returned.
do_test capi2-3.10b {db changes} {1}
do_test capi2-3.11 {
sqlite3_finalize $VM
} {SQLITE_OK}
do_test capi2-3.11b {db changes} {1}
do_test capi2-3.12 {
sqlite3_finalize $VM
} {SQLITE_MISUSE}
do_test capi2-3.13 {
set VM [sqlite3_prepare $DB {INSERT INTO t1 VALUES(1,3,4)} -1 TAIL]
list [sqlite3_step $VM] \
[sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_ERROR 0 {} {}}
# Update for v3: Preparing a statement does not affect the change counter.
# (Test result changes from 0 to 1). (Later:) change counter updates occur
# when sqlite3_step returns, not at finalize time.
do_test capi2-3.13b {db changes} {0}
do_test capi2-3.14 {
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
} {SQLITE_CONSTRAINT {column a is not unique}}
do_test capi2-3.15 {
set VM [sqlite3_prepare $DB {CREATE TABLE t2(a NOT NULL, b)} -1 TAIL]
set TAIL
} {}
do_test capi2-3.16 {
list [sqlite3_step $VM] \
[sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_DONE 0 {} {}}
do_test capi2-3.17 {
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
} {SQLITE_OK {not an error}}
do_test capi2-3.18 {
set VM [sqlite3_prepare $DB {INSERT INTO t2 VALUES(NULL,2)} -1 TAIL]
list [sqlite3_step $VM] \
[sqlite3_column_count $VM] \
[get_row_values $VM] \
[get_column_names $VM]
} {SQLITE_ERROR 0 {} {}}
do_test capi2-3.19 {
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
} {SQLITE_CONSTRAINT {t2.a may not be NULL}}
do_test capi2-3.20 {
execsql {
CREATE TABLE a1(message_id, name , UNIQUE(message_id, name) );
INSERT INTO a1 VALUES(1, 1);
}
} {}
do_test capi2-3.21 {
set VM [sqlite3_prepare $DB {INSERT INTO a1 VALUES(1, 1)} -1 TAIL]
sqlite3_step $VM
} {SQLITE_ERROR}
do_test capi2-3.22 {
sqlite3_errcode $DB
} {SQLITE_ERROR}
do_test capi2-3.23 {
sqlite3_finalize $VM
} {SQLITE_CONSTRAINT}
do_test capi2-3.24 {
sqlite3_errcode $DB
} {SQLITE_CONSTRAINT}
# Two or more virtual machines exists at the same time.
#
do_test capi2-4.1 {
set VM1 [sqlite3_prepare $DB {INSERT INTO t2 VALUES(1,2)} -1 TAIL]
set TAIL
} {}
do_test capi2-4.2 {
set VM2 [sqlite3_prepare $DB {INSERT INTO t2 VALUES(2,3)} -1 TAIL]
set TAIL
} {}
do_test capi2-4.3 {
set VM3 [sqlite3_prepare $DB {INSERT INTO t2 VALUES(3,4)} -1 TAIL]
set TAIL
} {}
do_test capi2-4.4 {
list [sqlite3_step $VM2] \
[sqlite3_column_count $VM2] \
[get_row_values $VM2] \
[get_column_names $VM2]
} {SQLITE_DONE 0 {} {}}
do_test capi2-4.5 {
execsql {SELECT * FROM t2 ORDER BY a}
} {2 3}
do_test capi2-4.6 {
sqlite3_finalize $VM2
} {SQLITE_OK}
do_test capi2-4.7 {
list [sqlite3_step $VM3] \
[sqlite3_column_count $VM3] \
[get_row_values $VM3] \
[get_column_names $VM3]
} {SQLITE_DONE 0 {} {}}
do_test capi2-4.8 {
execsql {SELECT * FROM t2 ORDER BY a}
} {2 3 3 4}
do_test capi2-4.9 {
sqlite3_finalize $VM3
} {SQLITE_OK}
do_test capi2-4.10 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_DONE 0 {} {}}
do_test capi2-4.11 {
execsql {SELECT * FROM t2 ORDER BY a}
} {1 2 2 3 3 4}
do_test capi2-4.12 {
sqlite3_finalize $VM1
} {SQLITE_OK}
# Interleaved SELECTs
#
do_test capi2-5.1 {
set VM1 [sqlite3_prepare $DB {SELECT * FROM t2} -1 TAIL]
set VM2 [sqlite3_prepare $DB {SELECT * FROM t2} -1 TAIL]
set VM3 [sqlite3_prepare $DB {SELECT * FROM t2} -1 TAIL]
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 2 {2 3} {a b {} {}}}
do_test capi2-5.2 {
list [sqlite3_step $VM2] \
[sqlite3_column_count $VM2] \
[get_row_values $VM2] \
[get_column_names $VM2]
} {SQLITE_ROW 2 {2 3} {a b {} {}}}
do_test capi2-5.3 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 2 {3 4} {a b {} {}}}
do_test capi2-5.4 {
list [sqlite3_step $VM3] \
[sqlite3_column_count $VM3] \
[get_row_values $VM3] \
[get_column_names $VM3]
} {SQLITE_ROW 2 {2 3} {a b {} {}}}
do_test capi2-5.5 {
list [sqlite3_step $VM3] \
[sqlite3_column_count $VM3] \
[get_row_values $VM3] \
[get_column_names $VM3]
} {SQLITE_ROW 2 {3 4} {a b {} {}}}
do_test capi2-5.6 {
list [sqlite3_step $VM3] \
[sqlite3_column_count $VM3] \
[get_row_values $VM3] \
[get_column_names $VM3]
} {SQLITE_ROW 2 {1 2} {a b {} {}}}
do_test capi2-5.7 {
list [sqlite3_step $VM3] \
[sqlite3_column_count $VM3] \
[get_row_values $VM3] \
[get_column_names $VM3]
} {SQLITE_DONE 2 {} {a b {} {}}}
do_test capi2-5.8 {
sqlite3_finalize $VM3
} {SQLITE_OK}
do_test capi2-5.9 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 2 {1 2} {a b {} {}}}
do_test capi2-5.10 {
sqlite3_finalize $VM1
} {SQLITE_OK}
do_test capi2-5.11 {
list [sqlite3_step $VM2] \
[sqlite3_column_count $VM2] \
[get_row_values $VM2] \
[get_column_names $VM2]
} {SQLITE_ROW 2 {3 4} {a b {} {}}}
do_test capi2-5.12 {
list [sqlite3_step $VM2] \
[sqlite3_column_count $VM2] \
[get_row_values $VM2] \
[get_column_names $VM2]
} {SQLITE_ROW 2 {1 2} {a b {} {}}}
do_test capi2-5.11 {
sqlite3_finalize $VM2
} {SQLITE_OK}
# Check for proper SQLITE_BUSY returns.
#
do_test capi2-6.1 {
execsql {
BEGIN;
CREATE TABLE t3(x counter);
INSERT INTO t3 VALUES(1);
INSERT INTO t3 VALUES(2);
INSERT INTO t3 SELECT x+2 FROM t3;
INSERT INTO t3 SELECT x+4 FROM t3;
INSERT INTO t3 SELECT x+8 FROM t3;
COMMIT;
}
set VM1 [sqlite3_prepare $DB {SELECT * FROM t3} -1 TAIL]
sqlite3 db2 test.db
execsql {BEGIN} db2
} {}
# Update for v3: BEGIN doesn't write-lock the database. It is quite
# difficult to get v3 to write-lock the database, which causes a few
# problems for test scripts.
#
# do_test capi2-6.2 {
# list [sqlite3_step $VM1] \
# [sqlite3_column_count $VM1] \
# [get_row_values $VM1] \
# [get_column_names $VM1]
# } {SQLITE_BUSY 0 {} {}}
do_test capi2-6.3 {
execsql {COMMIT} db2
} {}
do_test capi2-6.4 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 1 {x counter}}
do_test capi2-6.5 {
catchsql {INSERT INTO t3 VALUES(10);} db2
} {1 {database is locked}}
do_test capi2-6.6 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 2 {x counter}}
do_test capi2-6.7 {
execsql {SELECT * FROM t2} db2
} {2 3 3 4 1 2}
do_test capi2-6.8 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 3 {x counter}}
do_test capi2-6.9 {
execsql {SELECT * FROM t2}
} {2 3 3 4 1 2}
do_test capi2-6.10 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 4 {x counter}}
do_test capi2-6.11 {
execsql {BEGIN}
} {}
do_test capi2-6.12 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 5 {x counter}}
# A read no longer blocks a write in the same connection.
#do_test capi2-6.13 {
# catchsql {UPDATE t3 SET x=x+1}
#} {1 {database table is locked}}
do_test capi2-6.14 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 6 {x counter}}
do_test capi2-6.15 {
execsql {SELECT * FROM t1}
} {1 2 3}
do_test capi2-6.16 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 7 {x counter}}
do_test capi2-6.17 {
catchsql {UPDATE t1 SET b=b+1}
} {0 {}}
do_test capi2-6.18 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 8 {x counter}}
do_test capi2-6.19 {
execsql {SELECT * FROM t1}
} {1 3 3}
do_test capi2-6.20 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 9 {x counter}}
#do_test capi2-6.21 {
# execsql {ROLLBACK; SELECT * FROM t1}
#} {1 2 3}
do_test capi2-6.22 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 10 {x counter}}
#do_test capi2-6.23 {
# execsql {BEGIN TRANSACTION;}
#} {}
do_test capi2-6.24 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 11 {x counter}}
do_test capi2-6.25 {
execsql {
INSERT INTO t1 VALUES(2,3,4);
SELECT * FROM t1;
}
} {1 3 3 2 3 4}
do_test capi2-6.26 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 12 {x counter}}
do_test capi2-6.27 {
catchsql {
INSERT INTO t1 VALUES(2,4,5);
SELECT * FROM t1;
}
} {1 {column a is not unique}}
do_test capi2-6.28 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 13 {x counter}}
do_test capi2-6.99 {
sqlite3_finalize $VM1
} {SQLITE_OK}
catchsql {ROLLBACK}
do_test capi2-7.1 {
stepsql $DB {
SELECT * FROM t1
}
} {0 1 2 3}
do_test capi2-7.2 {
stepsql $DB {
PRAGMA count_changes=on
}
} {0}
do_test capi2-7.3 {
stepsql $DB {
UPDATE t1 SET a=a+10;
}
} {0 1}
do_test capi2-7.4 {
stepsql $DB {
INSERT INTO t1 SELECT a+1,b+1,c+1 FROM t1;
}
} {0 1}
do_test capi2-7.4b {sqlite3_changes $DB} {1}
do_test capi2-7.5 {
stepsql $DB {
UPDATE t1 SET a=a+10;
}
} {0 2}
do_test capi2-7.5b {sqlite3_changes $DB} {2}
do_test capi2-7.6 {
stepsql $DB {
SELECT * FROM t1;
}
} {0 21 2 3 22 3 4}
do_test capi2-7.7 {
stepsql $DB {
INSERT INTO t1 SELECT a+2,b+2,c+2 FROM t1;
}
} {0 2}
do_test capi2-7.8 {
sqlite3_changes $DB
} {2}
do_test capi2-7.9 {
stepsql $DB {
SELECT * FROM t1;
}
} {0 21 2 3 22 3 4 23 4 5 24 5 6}
do_test capi2-7.10 {
stepsql $DB {
UPDATE t1 SET a=a-20;
SELECT * FROM t1;
}
} {0 4 1 2 3 2 3 4 3 4 5 4 5 6}
# Update for version 3: A SELECT statement no longer resets the change
# counter (Test result changes from 0 to 4).
do_test capi2-7.11 {
sqlite3_changes $DB
} {4}
do_test capi2-7.11a {
execsql {SELECT count(*) FROM t1}
} {4}
ifcapable {explain} {
do_test capi2-7.12 {
btree_breakpoint
set x [stepsql $DB {EXPLAIN SELECT * FROM t1}]
lindex $x 0
} {0}
}
# Ticket #261 - make sure we can finalize before the end of a query.
#
do_test capi2-8.1 {
set VM1 [sqlite3_prepare $DB {SELECT * FROM t2} -1 TAIL]
sqlite3_finalize $VM1
} {SQLITE_OK}
# Tickets #384 and #385 - make sure the TAIL argument to sqlite3_prepare
# and all of the return pointers in sqlite_step can be null.
#
do_test capi2-9.1 {
set VM1 [sqlite3_prepare $DB {SELECT * FROM t2} -1 DUMMY]
sqlite3_step $VM1
sqlite3_finalize $VM1
} {SQLITE_OK}
# Test that passing a NULL pointer to sqlite3_finalize() or sqlite3_reset
# does not cause an error.
do_test capi2-10.1 {
sqlite3_finalize 0
} {SQLITE_OK}
do_test capi2-10.2 {
sqlite3_reset 0
} {SQLITE_OK}
#---------------------------------------------------------------------------
# The following tests - capi2-11.* - test the "column origin" APIs.
#
# sqlite3_column_origin_name()
# sqlite3_column_database_name()
# sqlite3_column_table_name()
#
ifcapable columnmetadata {
# This proc uses the database handle $::DB to compile the SQL statement passed
# as a parameter. The return value of this procedure is a list with one
# element for each column returned by the compiled statement. Each element of
# this list is itself a list of length three, consisting of the origin
# database, table and column for the corresponding returned column.
proc check_origins {sql} {
set ret [list]
set ::STMT [sqlite3_prepare $::DB $sql -1 dummy]
for {set i 0} {$i < [sqlite3_column_count $::STMT]} {incr i} {
lappend ret [list \
[sqlite3_column_database_name $::STMT $i] \
[sqlite3_column_table_name $::STMT $i] \
[sqlite3_column_origin_name $::STMT $i] \
]
}
sqlite3_finalize $::STMT
return $ret
}
do_test capi2-11.1 {
execsql {
CREATE TABLE tab1(col1, col2);
}
} {}
do_test capi2-11.2 {
check_origins {SELECT col2, col1 FROM tab1}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-11.3 {
check_origins {SELECT col2 AS hello, col1 AS world FROM tab1}
} [list {main tab1 col2} {main tab1 col1}]
ifcapable subquery {
do_test capi2-11.4 {
check_origins {SELECT b, a FROM (SELECT col1 AS a, col2 AS b FROM tab1)}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-11.5 {
check_origins {SELECT (SELECT col2 FROM tab1), (SELECT col1 FROM tab1)}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-11.6 {
check_origins {SELECT (SELECT col2), (SELECT col1) FROM tab1}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-11.7 {
check_origins {SELECT * FROM tab1}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-11.8 {
check_origins {SELECT * FROM (SELECT * FROM tab1)}
} [list {main tab1 col1} {main tab1 col2}]
}
ifcapable view&&subquery {
do_test capi2-12.1 {
execsql {
CREATE VIEW view1 AS SELECT * FROM tab1;
}
} {}
do_test capi2-12.2 {
check_origins {SELECT col2, col1 FROM view1}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-12.3 {
check_origins {SELECT col2 AS hello, col1 AS world FROM view1}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-12.4 {
check_origins {SELECT b, a FROM (SELECT col1 AS a, col2 AS b FROM view1)}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-12.5 {
check_origins {SELECT (SELECT col2 FROM view1), (SELECT col1 FROM view1)}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-12.6 {
check_origins {SELECT (SELECT col2), (SELECT col1) FROM view1}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-12.7 {
check_origins {SELECT * FROM view1}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-12.8 {
check_origins {select * from (select * from view1)}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-12.9 {
check_origins {select * from (select * from (select * from view1))}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-12.10 {
db close
sqlite3 db test.db
set ::DB [sqlite3_connection_pointer db]
check_origins {select * from (select * from (select * from view1))}
} [list {main tab1 col1} {main tab1 col2}]
# This view will thwart the flattening optimization.
do_test capi2-13.1 {
execsql {
CREATE VIEW view2 AS SELECT * FROM tab1 limit 10 offset 10;
}
} {}
breakpoint
do_test capi2-13.2 {
check_origins {SELECT col2, col1 FROM view2}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-13.3 {
check_origins {SELECT col2 AS hello, col1 AS world FROM view2}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-13.4 {
check_origins {SELECT b, a FROM (SELECT col1 AS a, col2 AS b FROM view2)}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-13.5 {
check_origins {SELECT (SELECT col2 FROM view2), (SELECT col1 FROM view2)}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-13.6 {
check_origins {SELECT (SELECT col2), (SELECT col1) FROM view2}
} [list {main tab1 col2} {main tab1 col1}]
do_test capi2-13.7 {
check_origins {SELECT * FROM view2}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-13.8 {
check_origins {select * from (select * from view2)}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-13.9 {
check_origins {select * from (select * from (select * from view2))}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-13.10 {
db close
sqlite3 db test.db
set ::DB [sqlite3_connection_pointer db]
check_origins {select * from (select * from (select * from view2))}
} [list {main tab1 col1} {main tab1 col2}]
do_test capi2-13.11 {
check_origins {select * from (select * from tab1 limit 10 offset 10)}
} [list {main tab1 col1} {main tab1 col2}]
}
} ;# ifcapable columnmetadata
db2 close
finish_test
File diff suppressed because it is too large Load Diff
+135
View File
@@ -0,0 +1,135 @@
# 2004 September 2
#
# 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 regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API and in
# particular the behavior of sqlite3_step() when trying to commit
# with lock contention.
#
# $Id: capi3b.test,v 1.3 2006/01/03 00:33:50 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set DB [sqlite3_connection_pointer db]
sqlite3 db2 test.db
set DB2 [sqlite3_connection_pointer db2]
# Create some data in the database
#
do_test capi3b-1.1 {
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
SELECT * FROM t1
}
} {1 2}
# Make sure the second database connection can see the data
#
do_test capi3b-1.2 {
execsql {
SELECT * FROM t1
} db2
} {1 2}
# First database connection acquires a shared lock
#
do_test capi3b-1.3 {
execsql {
BEGIN;
SELECT * FROM t1;
}
} {1 2}
# Second database connection tries to write. The sqlite3_step()
# function returns SQLITE_BUSY because it cannot commit.
#
do_test capi3b-1.4 {
set VM [sqlite3_prepare $DB2 {INSERT INTO t1 VALUES(3)} -1 TAIL]
sqlite3_step $VM
} SQLITE_BUSY
# The sqlite3_step call can be repeated multiple times.
#
do_test capi3b-1.5.1 {
sqlite3_step $VM
} SQLITE_BUSY
do_test capi3b-1.5.2 {
sqlite3_step $VM
} SQLITE_BUSY
# The first connection closes its transaction. This allows the second
# connections sqlite3_step to succeed.
#
do_test capi3b-1.6 {
execsql COMMIT
sqlite3_step $VM
} SQLITE_DONE
do_test capi3b-1.7 {
sqlite3_finalize $VM
} SQLITE_OK
do_test capi3b-1.8 {
execsql {SELECT * FROM t1} db2
} {1 2 3}
do_test capi3b-1.9 {
execsql {SELECT * FROM t1}
} {1 2 3}
# Start doing a SELECT with one connection. This gets a SHARED lock.
# Then do an INSERT with the other connection. The INSERT should
# not be able to complete until the SELECT finishes.
#
do_test capi3b-2.1 {
set VM1 [sqlite3_prepare $DB {SELECT * FROM t1} -1 TAIL]
sqlite3_step $VM1
} SQLITE_ROW
do_test capi3b-2.2 {
sqlite3_column_text $VM1 0
} 1
do_test capi3b-2.3 {
set VM2 [sqlite3_prepare $DB2 {INSERT INTO t1 VALUES(4)} -1 TAIL]
sqlite3_step $VM2
} SQLITE_BUSY
do_test capi3b-2.4 {
sqlite3_step $VM1
} SQLITE_ROW
do_test capi3b-2.5 {
sqlite3_column_text $VM1 0
} 2
do_test capi3b-2.6 {
sqlite3_step $VM2
} SQLITE_BUSY
do_test capi3b-2.7 {
sqlite3_step $VM1
} SQLITE_ROW
do_test capi3b-2.8 {
sqlite3_column_text $VM1 0
} 3
do_test capi3b-2.9 {
sqlite3_step $VM2
} SQLITE_BUSY
do_test capi3b-2.10 {
sqlite3_step $VM1
} SQLITE_DONE
do_test capi3b-2.11 {
sqlite3_step $VM2
} SQLITE_DONE
do_test capi3b-2.12 {
sqlite3_finalize $VM1
sqlite3_finalize $VM2
execsql {SELECT * FROM t1}
} {1 2 3 4}
catch {db2 close}
finish_test
+196
View File
@@ -0,0 +1,196 @@
# 2005 June 25
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the CAST operator.
#
# $Id: cast.test,v 1.5 2006/03/03 19:12:30 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if the build includes the CAST operator
ifcapable !cast {
finish_test
return
}
# Tests for the CAST( AS blob), CAST( AS text) and CAST( AS numeric) built-ins
#
ifcapable bloblit {
do_test cast-1.1 {
execsql {SELECT x'616263'}
} abc
do_test cast-1.2 {
execsql {SELECT typeof(x'616263')}
} blob
do_test cast-1.3 {
execsql {SELECT CAST(x'616263' AS text)}
} abc
do_test cast-1.4 {
execsql {SELECT typeof(CAST(x'616263' AS text))}
} text
do_test cast-1.5 {
execsql {SELECT CAST(x'616263' AS numeric)}
} 0
do_test cast-1.6 {
execsql {SELECT typeof(CAST(x'616263' AS numeric))}
} integer
do_test cast-1.7 {
execsql {SELECT CAST(x'616263' AS blob)}
} abc
do_test cast-1.8 {
execsql {SELECT typeof(CAST(x'616263' AS blob))}
} blob
do_test cast-1.9 {
execsql {SELECT CAST(x'616263' AS integer)}
} 0
do_test cast-1.10 {
execsql {SELECT typeof(CAST(x'616263' AS integer))}
} integer
}
do_test cast-1.11 {
execsql {SELECT null}
} {{}}
do_test cast-1.12 {
execsql {SELECT typeof(NULL)}
} null
do_test cast-1.13 {
execsql {SELECT CAST(NULL AS text)}
} {{}}
do_test cast-1.14 {
execsql {SELECT typeof(CAST(NULL AS text))}
} null
do_test cast-1.15 {
execsql {SELECT CAST(NULL AS numeric)}
} {{}}
do_test cast-1.16 {
execsql {SELECT typeof(CAST(NULL AS numeric))}
} null
do_test cast-1.17 {
execsql {SELECT CAST(NULL AS blob)}
} {{}}
do_test cast-1.18 {
execsql {SELECT typeof(CAST(NULL AS blob))}
} null
do_test cast-1.19 {
execsql {SELECT CAST(NULL AS integer)}
} {{}}
do_test cast-1.20 {
execsql {SELECT typeof(CAST(NULL AS integer))}
} null
do_test cast-1.21 {
execsql {SELECT 123}
} {123}
do_test cast-1.22 {
execsql {SELECT typeof(123)}
} integer
do_test cast-1.23 {
execsql {SELECT CAST(123 AS text)}
} {123}
do_test cast-1.24 {
execsql {SELECT typeof(CAST(123 AS text))}
} text
do_test cast-1.25 {
execsql {SELECT CAST(123 AS numeric)}
} 123
do_test cast-1.26 {
execsql {SELECT typeof(CAST(123 AS numeric))}
} integer
do_test cast-1.27 {
execsql {SELECT CAST(123 AS blob)}
} {123}
do_test cast-1.28 {
execsql {SELECT typeof(CAST(123 AS blob))}
} blob
do_test cast-1.29 {
execsql {SELECT CAST(123 AS integer)}
} {123}
do_test cast-1.30 {
execsql {SELECT typeof(CAST(123 AS integer))}
} integer
do_test cast-1.31 {
execsql {SELECT 123.456}
} {123.456}
do_test cast-1.32 {
execsql {SELECT typeof(123.456)}
} real
do_test cast-1.33 {
execsql {SELECT CAST(123.456 AS text)}
} {123.456}
do_test cast-1.34 {
execsql {SELECT typeof(CAST(123.456 AS text))}
} text
do_test cast-1.35 {
execsql {SELECT CAST(123.456 AS numeric)}
} 123.456
do_test cast-1.36 {
execsql {SELECT typeof(CAST(123.456 AS numeric))}
} real
do_test cast-1.37 {
execsql {SELECT CAST(123.456 AS blob)}
} {123.456}
do_test cast-1.38 {
execsql {SELECT typeof(CAST(123.456 AS blob))}
} blob
do_test cast-1.39 {
execsql {SELECT CAST(123.456 AS integer)}
} {123}
do_test cast-1.38 {
execsql {SELECT typeof(CAST(123.456 AS integer))}
} integer
do_test cast-1.41 {
execsql {SELECT '123abc'}
} {123abc}
do_test cast-1.42 {
execsql {SELECT typeof('123abc')}
} text
do_test cast-1.43 {
execsql {SELECT CAST('123abc' AS text)}
} {123abc}
do_test cast-1.44 {
execsql {SELECT typeof(CAST('123abc' AS text))}
} text
do_test cast-1.45 {
execsql {SELECT CAST('123abc' AS numeric)}
} 123
do_test cast-1.46 {
execsql {SELECT typeof(CAST('123abc' AS numeric))}
} integer
do_test cast-1.47 {
execsql {SELECT CAST('123abc' AS blob)}
} {123abc}
do_test cast-1.48 {
execsql {SELECT typeof(CAST('123abc' AS blob))}
} blob
do_test cast-1.49 {
execsql {SELECT CAST('123abc' AS integer)}
} 123
do_test cast-1.50 {
execsql {SELECT typeof(CAST('123abc' AS integer))}
} integer
do_test cast-1.51 {
execsql {SELECT CAST('123.5abc' AS numeric)}
} 123.5
do_test cast-1.53 {
execsql {SELECT CAST('123.5abc' AS integer)}
} 123
# Ticket #1662. Ignore leading spaces in numbers when casting.
#
do_test cast-2.1 {
execsql {SELECT CAST(' 123' AS integer)}
} 123
do_test cast-2.2 {
execsql {SELECT CAST(' -123.456' AS real)}
} -123.456
finish_test
+351
View File
@@ -0,0 +1,351 @@
# 2005 November 2
#
# 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 regression tests for SQLite library. The
# focus of this file is testing CHECK constraints
#
# $Id: check.test,v 1.10 2006/06/20 11:01:09 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if the build includes support for CHECK constraints
ifcapable !check {
finish_test
return
}
do_test check-1.1 {
execsql {
CREATE TABLE t1(
x INTEGER CHECK( x<5 ),
y REAL CHECK( y>x )
);
}
} {}
do_test check-1.2 {
execsql {
INSERT INTO t1 VALUES(3,4);
SELECT * FROM t1;
}
} {3 4.0}
do_test check-1.3 {
catchsql {
INSERT INTO t1 VALUES(6,7);
}
} {1 {constraint failed}}
do_test check-1.4 {
execsql {
SELECT * FROM t1;
}
} {3 4.0}
do_test check-1.5 {
catchsql {
INSERT INTO t1 VALUES(4,3);
}
} {1 {constraint failed}}
do_test check-1.6 {
execsql {
SELECT * FROM t1;
}
} {3 4.0}
do_test check-1.7 {
catchsql {
INSERT INTO t1 VALUES(NULL,6);
}
} {0 {}}
do_test check-1.8 {
execsql {
SELECT * FROM t1;
}
} {3 4.0 {} 6.0}
do_test check-1.9 {
catchsql {
INSERT INTO t1 VALUES(2,NULL);
}
} {0 {}}
do_test check-1.10 {
execsql {
SELECT * FROM t1;
}
} {3 4.0 {} 6.0 2 {}}
do_test check-1.11 {
execsql {
DELETE FROM t1 WHERE x IS NULL OR x!=3;
UPDATE t1 SET x=2 WHERE x==3;
SELECT * FROM t1;
}
} {2 4.0}
do_test check-1.12 {
catchsql {
UPDATE t1 SET x=7 WHERE x==2
}
} {1 {constraint failed}}
do_test check-1.13 {
execsql {
SELECT * FROM t1;
}
} {2 4.0}
do_test check-1.14 {
catchsql {
UPDATE t1 SET x=5 WHERE x==2
}
} {1 {constraint failed}}
do_test check-1.15 {
execsql {
SELECT * FROM t1;
}
} {2 4.0}
do_test check-1.16 {
catchsql {
UPDATE t1 SET x=4, y=11 WHERE x==2
}
} {0 {}}
do_test check-1.17 {
execsql {
SELECT * FROM t1;
}
} {4 11.0}
do_test check-2.1 {
execsql {
CREATE TABLE t2(
x INTEGER CHECK( typeof(coalesce(x,0))=="integer" ),
y REAL CHECK( typeof(coalesce(y,0.1))=="real" ),
z TEXT CHECK( typeof(coalesce(z,''))=="text" )
);
}
} {}
do_test check-2.2 {
execsql {
INSERT INTO t2 VALUES(1,2.2,'three');
SELECT * FROM t2;
}
} {1 2.2 three}
do_test check-2.3 {
execsql {
INSERT INTO t2 VALUES(NULL, NULL, NULL);
SELECT * FROM t2;
}
} {1 2.2 three {} {} {}}
do_test check-2.4 {
catchsql {
INSERT INTO t2 VALUES(1.1, NULL, NULL);
}
} {1 {constraint failed}}
do_test check-2.5 {
catchsql {
INSERT INTO t2 VALUES(NULL, 5, NULL);
}
} {1 {constraint failed}}
do_test check-2.6 {
catchsql {
INSERT INTO t2 VALUES(NULL, NULL, 3.14159);
}
} {1 {constraint failed}}
ifcapable subquery {
do_test check-3.1 {
catchsql {
CREATE TABLE t3(
x, y, z,
CHECK( x<(SELECT min(x) FROM t1) )
);
}
} {1 {subqueries prohibited in CHECK constraints}}
}
do_test check-3.2 {
execsql {
SELECT name FROM sqlite_master ORDER BY name
}
} {t1 t2}
do_test check-3.3 {
catchsql {
CREATE TABLE t3(
x, y, z,
CHECK( q<x )
);
}
} {1 {no such column: q}}
do_test check-3.4 {
execsql {
SELECT name FROM sqlite_master ORDER BY name
}
} {t1 t2}
do_test check-3.5 {
catchsql {
CREATE TABLE t3(
x, y, z,
CHECK( t2.x<x )
);
}
} {1 {no such column: t2.x}}
do_test check-3.6 {
execsql {
SELECT name FROM sqlite_master ORDER BY name
}
} {t1 t2}
do_test check-3.7 {
catchsql {
CREATE TABLE t3(
x, y, z,
CHECK( t3.x<25 )
);
}
} {0 {}}
do_test check-3.8 {
execsql {
INSERT INTO t3 VALUES(1,2,3);
SELECT * FROM t3;
}
} {1 2 3}
do_test check-3.9 {
catchsql {
INSERT INTO t3 VALUES(111,222,333);
}
} {1 {constraint failed}}
do_test check-4.1 {
execsql {
CREATE TABLE t4(x, y,
CHECK (
x+y==11
OR x*y==12
OR x/y BETWEEN 5 AND 8
OR -x==y+10
)
);
}
} {}
do_test check-4.2 {
execsql {
INSERT INTO t4 VALUES(1,10);
SELECT * FROM t4
}
} {1 10}
do_test check-4.3 {
execsql {
UPDATE t4 SET x=4, y=3;
SELECT * FROM t4
}
} {4 3}
do_test check-4.3 {
execsql {
UPDATE t4 SET x=12, y=2;
SELECT * FROM t4
}
} {12 2}
do_test check-4.4 {
execsql {
UPDATE t4 SET x=12, y=-22;
SELECT * FROM t4
}
} {12 -22}
do_test check-4.5 {
catchsql {
UPDATE t4 SET x=0, y=1;
}
} {1 {constraint failed}}
do_test check-4.6 {
execsql {
SELECT * FROM t4;
}
} {12 -22}
do_test check-4.7 {
execsql {
PRAGMA ignore_check_constraints=ON;
UPDATE t4 SET x=0, y=1;
SELECT * FROM t4;
}
} {0 1}
do_test check-4.8 {
catchsql {
PRAGMA ignore_check_constraints=OFF;
UPDATE t4 SET x=0, y=2;
}
} {1 {constraint failed}}
ifcapable vacuum {
do_test check_4.9 {
catchsql {
VACUUM
}
} {0 {}}
}
do_test check-5.1 {
catchsql {
CREATE TABLE t5(x, y,
CHECK( x*y<:abc )
);
}
} {1 {parameters prohibited in CHECK constraints}}
do_test check-5.2 {
catchsql {
CREATE TABLE t5(x, y,
CHECK( x*y<? )
);
}
} {1 {parameters prohibited in CHECK constraints}}
ifcapable conflict {
do_test check-6.1 {
execsql {SELECT * FROM t1}
} {4 11.0}
do_test check-6.2 {
execsql {
UPDATE OR IGNORE t1 SET x=5;
SELECT * FROM t1;
}
} {4 11.0}
do_test check-6.3 {
execsql {
INSERT OR IGNORE INTO t1 VALUES(5,4.0);
SELECT * FROM t1;
}
} {4 11.0}
do_test check-6.4 {
execsql {
INSERT OR IGNORE INTO t1 VALUES(2,20.0);
SELECT * FROM t1;
}
} {4 11.0 2 20.0}
do_test check-6.5 {
catchsql {
UPDATE OR FAIL t1 SET x=7-x, y=y+1;
}
} {1 {constraint failed}}
do_test check-6.6 {
execsql {
SELECT * FROM t1;
}
} {3 12.0 2 20.0}
do_test check-6.7 {
catchsql {
BEGIN;
INSERT INTO t1 VALUES(1,30.0);
INSERT OR ROLLBACK INTO t1 VALUES(8,40.0);
}
} {1 {constraint failed}}
do_test check-6.8 {
catchsql {
COMMIT;
}
} {1 {cannot commit - no transaction is active}}
do_test check-6.9 {
execsql {
SELECT * FROM t1
}
} {3 12.0 2 20.0}
}
finish_test
+229
View File
@@ -0,0 +1,229 @@
#
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is page cache subsystem.
#
# $Id: collate1.test,v 1.4 2005/11/01 15:48:25 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
#
# Tests are roughly organised as follows:
#
# collate1-1.* - Single-field ORDER BY with an explicit COLLATE clause.
# collate1-2.* - Multi-field ORDER BY with an explicit COLLATE clause.
# collate1-3.* - ORDER BY using a default collation type. Also that an
# explict collate type overrides a default collate type.
# collate1-4.* - ORDER BY using a data type.
#
#
# Collation type 'HEX'. If an argument can be interpreted as a hexadecimal
# number, then it is converted to one before the comparison is performed.
# Numbers are less than other strings. If neither argument is a number,
# [string compare] is used.
#
db collate HEX hex_collate
proc hex_collate {lhs rhs} {
set lhs_ishex [regexp {^(0x|)[1234567890abcdefABCDEF]+$} $lhs]
set rhs_ishex [regexp {^(0x|)[1234567890abcdefABCDEF]+$} $rhs]
if {$lhs_ishex && $rhs_ishex} {
set lhsx [scan $lhs %x]
set rhsx [scan $rhs %x]
if {$lhs < $rhs} {return -1}
if {$lhs == $rhs} {return 0}
if {$lhs > $rhs} {return 1}
}
if {$lhs_ishex} {
return -1;
}
if {$rhs_ishex} {
return 1;
}
return [string compare $lhs $rhs]
}
db function hex {format 0x%X}
# Mimic the SQLite 2 collation type NUMERIC.
db collate numeric numeric_collate
proc numeric_collate {lhs rhs} {
if {$lhs == $rhs} {return 0}
return [expr ($lhs>$rhs)?1:-1]
}
do_test collate1-1.0 {
execsql {
CREATE TABLE collate1t1(c1, c2);
INSERT INTO collate1t1 VALUES(45, hex(45));
INSERT INTO collate1t1 VALUES(NULL, NULL);
INSERT INTO collate1t1 VALUES(281, hex(281));
}
} {}
do_test collate1-1.1 {
execsql {
SELECT c2 FROM collate1t1 ORDER BY 1;
}
} {{} 0x119 0x2D}
do_test collate1-1.2 {
execsql {
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex;
}
} {{} 0x2D 0x119}
do_test collate1-1.3 {
execsql {
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex DESC;
}
} {0x119 0x2D {}}
do_test collate1-1.4 {
execsql {
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex ASC;
}
} {{} 0x2D 0x119}
do_test collate1-1.5 {
execsql {
DROP TABLE collate1t1;
}
} {}
do_test collate1-2.0 {
execsql {
CREATE TABLE collate1t1(c1, c2);
INSERT INTO collate1t1 VALUES('5', '0x11');
INSERT INTO collate1t1 VALUES('5', '0xA');
INSERT INTO collate1t1 VALUES(NULL, NULL);
INSERT INTO collate1t1 VALUES('7', '0xA');
INSERT INTO collate1t1 VALUES('11', '0x11');
INSERT INTO collate1t1 VALUES('11', '0x101');
}
} {}
do_test collate1-2.2 {
execsql {
SELECT c1, c2 FROM collate1t1 ORDER BY 1 COLLATE numeric, 2 COLLATE hex;
}
} {{} {} 5 0xA 5 0x11 7 0xA 11 0x11 11 0x101}
do_test collate1-2.3 {
execsql {
SELECT c1, c2 FROM collate1t1 ORDER BY 1 COLLATE binary, 2 COLLATE hex;
}
} {{} {} 11 0x11 11 0x101 5 0xA 5 0x11 7 0xA}
do_test collate1-2.4 {
execsql {
SELECT c1, c2 FROM collate1t1 ORDER BY 1 COLLATE binary DESC, 2 COLLATE hex;
}
} {7 0xA 5 0xA 5 0x11 11 0x11 11 0x101 {} {}}
do_test collate1-2.5 {
execsql {
SELECT c1, c2 FROM collate1t1
ORDER BY 1 COLLATE binary DESC, 2 COLLATE hex DESC;
}
} {7 0xA 5 0x11 5 0xA 11 0x101 11 0x11 {} {}}
do_test collate1-2.6 {
execsql {
SELECT c1, c2 FROM collate1t1
ORDER BY 1 COLLATE binary ASC, 2 COLLATE hex ASC;
}
} {{} {} 11 0x11 11 0x101 5 0xA 5 0x11 7 0xA}
do_test collate1-2.7 {
execsql {
DROP TABLE collate1t1;
}
} {}
#
# These tests ensure that the default collation type for a column is used
# by an ORDER BY clause correctly. The focus is all the different ways
# the column can be referenced. i.e. a, collate2t1.a, main.collate2t1.a etc.
#
do_test collate1-3.0 {
execsql {
CREATE TABLE collate1t1(a COLLATE hex, b);
INSERT INTO collate1t1 VALUES( '0x5', 5 );
INSERT INTO collate1t1 VALUES( '1', 1 );
INSERT INTO collate1t1 VALUES( '0x45', 69 );
INSERT INTO collate1t1 VALUES( NULL, NULL );
SELECT * FROM collate1t1 ORDER BY a;
}
} {{} {} 1 1 0x5 5 0x45 69}
do_test collate1-3.1 {
execsql {
SELECT * FROM collate1t1 ORDER BY 1;
}
} {{} {} 1 1 0x5 5 0x45 69}
do_test collate1-3.2 {
execsql {
SELECT * FROM collate1t1 ORDER BY collate1t1.a;
}
} {{} {} 1 1 0x5 5 0x45 69}
do_test collate1-3.3 {
execsql {
SELECT * FROM collate1t1 ORDER BY main.collate1t1.a;
}
} {{} {} 1 1 0x5 5 0x45 69}
do_test collate1-3.4 {
execsql {
SELECT a as c1, b as c2 FROM collate1t1 ORDER BY c1;
}
} {{} {} 1 1 0x5 5 0x45 69}
do_test collate1-3.5 {
execsql {
SELECT a as c1, b as c2 FROM collate1t1 ORDER BY c1 COLLATE binary;
}
} {{} {} 0x45 69 0x5 5 1 1}
do_test collate1-3.6 {
execsql {
DROP TABLE collate1t1;
}
} {}
# Update for SQLite version 3. The collate1-4.* test cases were written
# before manifest types were introduced. The following test cases still
# work, due to the 'affinity' mechanism, but they don't prove anything
# about collation sequences.
#
do_test collate1-4.0 {
execsql {
CREATE TABLE collate1t1(c1 numeric, c2 text);
INSERT INTO collate1t1 VALUES(1, 1);
INSERT INTO collate1t1 VALUES(12, 12);
INSERT INTO collate1t1 VALUES(NULL, NULL);
INSERT INTO collate1t1 VALUES(101, 101);
}
} {}
do_test collate1-4.1 {
execsql {
SELECT c1 FROM collate1t1 ORDER BY 1;
}
} {{} 1 12 101}
do_test collate1-4.2 {
execsql {
SELECT c2 FROM collate1t1 ORDER BY 1;
}
} {{} 1 101 12}
do_test collate1-4.3 {
execsql {
SELECT c2+0 FROM collate1t1 ORDER BY 1;
}
} {{} 1 12 101}
do_test collate1-4.4 {
execsql {
SELECT c1||'' FROM collate1t1 ORDER BY 1;
}
} {{} 1 101 12}
do_test collate1-4.5 {
execsql {
DROP TABLE collate1t1;
}
} {}
finish_test
+613
View File
@@ -0,0 +1,613 @@
#
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is page cache subsystem.
#
# $Id: collate2.test,v 1.4 2005/01/21 03:12:16 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
#
# Tests are organised as follows:
#
# collate2-1.* WHERE <expr> expressions (sqliteExprIfTrue).
# collate2-2.* WHERE NOT <expr> expressions (sqliteExprIfFalse).
# collate2-3.* SELECT <expr> expressions (sqliteExprCode).
# collate2-4.* Precedence of collation/data types in binary comparisons
# collate2-5.* JOIN syntax.
#
# Create a collation type BACKWARDS for use in testing. This collation type
# is similar to the built-in TEXT collation type except the order of
# characters in each string is reversed before the comparison is performed.
db collate BACKWARDS backwards_collate
proc backwards_collate {a b} {
set ra {};
set rb {}
foreach c [split $a {}] { set ra $c$ra }
foreach c [split $b {}] { set rb $c$rb }
return [string compare $ra $rb]
}
# The following values are used in these tests:
# NULL aa ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB
#
# The collation orders for each of the tested collation types are:
#
# BINARY: NULL AA AB Aa Ab BA BB Ba Bb aA aB aa ab bA bB ba bb
# NOCASE: NULL aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB
# BACKWARDS: NULL AA BA aA bA AB BB aB bB Aa Ba aa ba Ab Bb ab bb
#
# These tests verify that the default collation type for a column is used
# for comparison operators (<, >, <=, >=, =) involving that column and
# an expression that is not a column with a default collation type.
#
# The collation sequences BINARY and NOCASE are built-in, the BACKWARDS
# collation sequence is implemented by the TCL proc backwards_collate
# above.
#
do_test collate2-1.0 {
execsql {
CREATE TABLE collate2t1(
a COLLATE BINARY,
b COLLATE NOCASE,
c COLLATE BACKWARDS
);
INSERT INTO collate2t1 VALUES( NULL, NULL, NULL );
INSERT INTO collate2t1 VALUES( 'aa', 'aa', 'aa' );
INSERT INTO collate2t1 VALUES( 'ab', 'ab', 'ab' );
INSERT INTO collate2t1 VALUES( 'ba', 'ba', 'ba' );
INSERT INTO collate2t1 VALUES( 'bb', 'bb', 'bb' );
INSERT INTO collate2t1 VALUES( 'aA', 'aA', 'aA' );
INSERT INTO collate2t1 VALUES( 'aB', 'aB', 'aB' );
INSERT INTO collate2t1 VALUES( 'bA', 'bA', 'bA' );
INSERT INTO collate2t1 VALUES( 'bB', 'bB', 'bB' );
INSERT INTO collate2t1 VALUES( 'Aa', 'Aa', 'Aa' );
INSERT INTO collate2t1 VALUES( 'Ab', 'Ab', 'Ab' );
INSERT INTO collate2t1 VALUES( 'Ba', 'Ba', 'Ba' );
INSERT INTO collate2t1 VALUES( 'Bb', 'Bb', 'Bb' );
INSERT INTO collate2t1 VALUES( 'AA', 'AA', 'AA' );
INSERT INTO collate2t1 VALUES( 'AB', 'AB', 'AB' );
INSERT INTO collate2t1 VALUES( 'BA', 'BA', 'BA' );
INSERT INTO collate2t1 VALUES( 'BB', 'BB', 'BB' );
}
if {[info exists collate_test_use_index]} {
execsql {
CREATE INDEX collate2t1_i1 ON collate2t1(a);
CREATE INDEX collate2t1_i2 ON collate2t1(b);
CREATE INDEX collate2t1_i3 ON collate2t1(c);
}
}
} {}
do_test collate2-1.1 {
execsql {
SELECT a FROM collate2t1 WHERE a > 'aa' ORDER BY 1;
}
} {ab bA bB ba bb}
do_test collate2-1.2 {
execsql {
SELECT b FROM collate2t1 WHERE b > 'aa' ORDER BY 1, oid;
}
} {ab aB Ab AB ba bA Ba BA bb bB Bb BB}
do_test collate2-1.3 {
execsql {
SELECT c FROM collate2t1 WHERE c > 'aa' ORDER BY 1;
}
} {ba Ab Bb ab bb}
do_test collate2-1.4 {
execsql {
SELECT a FROM collate2t1 WHERE a < 'aa' ORDER BY 1;
}
} {AA AB Aa Ab BA BB Ba Bb aA aB}
do_test collate2-1.5 {
execsql {
SELECT b FROM collate2t1 WHERE b < 'aa' ORDER BY 1, oid;
}
} {}
do_test collate2-1.6 {
execsql {
SELECT c FROM collate2t1 WHERE c < 'aa' ORDER BY 1;
}
} {AA BA aA bA AB BB aB bB Aa Ba}
do_test collate2-1.7 {
execsql {
SELECT a FROM collate2t1 WHERE a = 'aa';
}
} {aa}
do_test collate2-1.8 {
execsql {
SELECT b FROM collate2t1 WHERE b = 'aa' ORDER BY oid;
}
} {aa aA Aa AA}
do_test collate2-1.9 {
execsql {
SELECT c FROM collate2t1 WHERE c = 'aa';
}
} {aa}
do_test collate2-1.10 {
execsql {
SELECT a FROM collate2t1 WHERE a >= 'aa' ORDER BY 1;
}
} {aa ab bA bB ba bb}
do_test collate2-1.11 {
execsql {
SELECT b FROM collate2t1 WHERE b >= 'aa' ORDER BY 1, oid;
}
} {aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB}
do_test collate2-1.12 {
execsql {
SELECT c FROM collate2t1 WHERE c >= 'aa' ORDER BY 1;
}
} {aa ba Ab Bb ab bb}
do_test collate2-1.13 {
execsql {
SELECT a FROM collate2t1 WHERE a <= 'aa' ORDER BY 1;
}
} {AA AB Aa Ab BA BB Ba Bb aA aB aa}
do_test collate2-1.14 {
execsql {
SELECT b FROM collate2t1 WHERE b <= 'aa' ORDER BY 1, oid;
}
} {aa aA Aa AA}
do_test collate2-1.15 {
execsql {
SELECT c FROM collate2t1 WHERE c <= 'aa' ORDER BY 1;
}
} {AA BA aA bA AB BB aB bB Aa Ba aa}
do_test collate2-1.16 {
execsql {
SELECT a FROM collate2t1 WHERE a BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
}
} {Aa Ab BA BB Ba Bb}
do_test collate2-1.17 {
execsql {
SELECT b FROM collate2t1 WHERE b BETWEEN 'Aa' AND 'Bb' ORDER BY 1, oid;
}
} {aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB}
do_test collate2-1.18 {
execsql {
SELECT c FROM collate2t1 WHERE c BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
}
} {Aa Ba aa ba Ab Bb}
do_test collate2-1.19 {
execsql {
SELECT a FROM collate2t1 WHERE
CASE a WHEN 'aa' THEN 1 ELSE 0 END
ORDER BY 1, oid;
}
} {aa}
do_test collate2-1.20 {
execsql {
SELECT b FROM collate2t1 WHERE
CASE b WHEN 'aa' THEN 1 ELSE 0 END
ORDER BY 1, oid;
}
} {aa aA Aa AA}
do_test collate2-1.21 {
execsql {
SELECT c FROM collate2t1 WHERE
CASE c WHEN 'aa' THEN 1 ELSE 0 END
ORDER BY 1, oid;
}
} {aa}
ifcapable subquery {
do_test collate2-1.22 {
execsql {
SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb') ORDER BY 1, oid;
}
} {aa bb}
do_test collate2-1.23 {
execsql {
SELECT b FROM collate2t1 WHERE b IN ('aa', 'bb') ORDER BY 1, oid;
}
} {aa aA Aa AA bb bB Bb BB}
do_test collate2-1.24 {
execsql {
SELECT c FROM collate2t1 WHERE c IN ('aa', 'bb') ORDER BY 1, oid;
}
} {aa bb}
do_test collate2-1.25 {
execsql {
SELECT a FROM collate2t1
WHERE a IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
}
} {aa bb}
do_test collate2-1.26 {
execsql {
SELECT b FROM collate2t1
WHERE b IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
}
} {aa bb aA bB Aa Bb AA BB}
do_test collate2-1.27 {
execsql {
SELECT c FROM collate2t1
WHERE c IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
}
} {aa bb}
} ;# ifcapable subquery
do_test collate2-2.1 {
execsql {
SELECT a FROM collate2t1 WHERE NOT a > 'aa' ORDER BY 1;
}
} {AA AB Aa Ab BA BB Ba Bb aA aB aa}
do_test collate2-2.2 {
execsql {
SELECT b FROM collate2t1 WHERE NOT b > 'aa' ORDER BY 1, oid;
}
} {aa aA Aa AA}
do_test collate2-2.3 {
execsql {
SELECT c FROM collate2t1 WHERE NOT c > 'aa' ORDER BY 1;
}
} {AA BA aA bA AB BB aB bB Aa Ba aa}
do_test collate2-2.4 {
execsql {
SELECT a FROM collate2t1 WHERE NOT a < 'aa' ORDER BY 1;
}
} {aa ab bA bB ba bb}
do_test collate2-2.5 {
execsql {
SELECT b FROM collate2t1 WHERE NOT b < 'aa' ORDER BY 1, oid;
}
} {aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB}
do_test collate2-2.6 {
execsql {
SELECT c FROM collate2t1 WHERE NOT c < 'aa' ORDER BY 1;
}
} {aa ba Ab Bb ab bb}
do_test collate2-2.7 {
execsql {
SELECT a FROM collate2t1 WHERE NOT a = 'aa';
}
} {ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
do_test collate2-2.8 {
execsql {
SELECT b FROM collate2t1 WHERE NOT b = 'aa';
}
} {ab ba bb aB bA bB Ab Ba Bb AB BA BB}
do_test collate2-2.9 {
execsql {
SELECT c FROM collate2t1 WHERE NOT c = 'aa';
}
} {ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
do_test collate2-2.10 {
execsql {
SELECT a FROM collate2t1 WHERE NOT a >= 'aa' ORDER BY 1;
}
} {AA AB Aa Ab BA BB Ba Bb aA aB}
do_test collate2-2.11 {
execsql {
SELECT b FROM collate2t1 WHERE NOT b >= 'aa' ORDER BY 1, oid;
}
} {}
do_test collate2-2.12 {
execsql {
SELECT c FROM collate2t1 WHERE NOT c >= 'aa' ORDER BY 1;
}
} {AA BA aA bA AB BB aB bB Aa Ba}
do_test collate2-2.13 {
execsql {
SELECT a FROM collate2t1 WHERE NOT a <= 'aa' ORDER BY 1;
}
} {ab bA bB ba bb}
do_test collate2-2.14 {
execsql {
SELECT b FROM collate2t1 WHERE NOT b <= 'aa' ORDER BY 1, oid;
}
} {ab aB Ab AB ba bA Ba BA bb bB Bb BB}
do_test collate2-2.15 {
execsql {
SELECT c FROM collate2t1 WHERE NOT c <= 'aa' ORDER BY 1;
}
} {ba Ab Bb ab bb}
do_test collate2-2.16 {
execsql {
SELECT a FROM collate2t1 WHERE a NOT BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
}
} {AA AB aA aB aa ab bA bB ba bb}
do_test collate2-2.17 {
execsql {
SELECT b FROM collate2t1 WHERE b NOT BETWEEN 'Aa' AND 'Bb' ORDER BY 1, oid;
}
} {}
do_test collate2-2.18 {
execsql {
SELECT c FROM collate2t1 WHERE c NOT BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
}
} {AA BA aA bA AB BB aB bB ab bb}
do_test collate2-2.19 {
execsql {
SELECT a FROM collate2t1 WHERE NOT CASE a WHEN 'aa' THEN 1 ELSE 0 END;
}
} {{} ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
do_test collate2-2.20 {
execsql {
SELECT b FROM collate2t1 WHERE NOT CASE b WHEN 'aa' THEN 1 ELSE 0 END;
}
} {{} ab ba bb aB bA bB Ab Ba Bb AB BA BB}
do_test collate2-2.21 {
execsql {
SELECT c FROM collate2t1 WHERE NOT CASE c WHEN 'aa' THEN 1 ELSE 0 END;
}
} {{} ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
ifcapable subquery {
do_test collate2-2.22 {
execsql {
SELECT a FROM collate2t1 WHERE NOT a IN ('aa', 'bb');
}
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
do_test collate2-2.23 {
execsql {
SELECT b FROM collate2t1 WHERE NOT b IN ('aa', 'bb');
}
} {ab ba aB bA Ab Ba AB BA}
do_test collate2-2.24 {
execsql {
SELECT c FROM collate2t1 WHERE NOT c IN ('aa', 'bb');
}
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
do_test collate2-2.25 {
execsql {
SELECT a FROM collate2t1
WHERE NOT a IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
}
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
do_test collate2-2.26 {
execsql {
SELECT b FROM collate2t1
WHERE NOT b IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
}
} {ab ba aB bA Ab Ba AB BA}
do_test collate2-2.27 {
execsql {
SELECT c FROM collate2t1
WHERE NOT c IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
}
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
}
do_test collate2-3.1 {
execsql {
SELECT a > 'aa' FROM collate2t1;
}
} {{} 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0}
do_test collate2-3.2 {
execsql {
SELECT b > 'aa' FROM collate2t1;
}
} {{} 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1}
do_test collate2-3.3 {
execsql {
SELECT c > 'aa' FROM collate2t1;
}
} {{} 0 1 1 1 0 0 0 0 0 1 0 1 0 0 0 0}
do_test collate2-3.4 {
execsql {
SELECT a < 'aa' FROM collate2t1;
}
} {{} 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1}
do_test collate2-3.5 {
execsql {
SELECT b < 'aa' FROM collate2t1;
}
} {{} 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.6 {
execsql {
SELECT c < 'aa' FROM collate2t1;
}
} {{} 0 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1}
do_test collate2-3.7 {
execsql {
SELECT a = 'aa' FROM collate2t1;
}
} {{} 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.8 {
execsql {
SELECT b = 'aa' FROM collate2t1;
}
} {{} 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0}
do_test collate2-3.9 {
execsql {
SELECT c = 'aa' FROM collate2t1;
}
} {{} 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.10 {
execsql {
SELECT a <= 'aa' FROM collate2t1;
}
} {{} 1 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1}
do_test collate2-3.11 {
execsql {
SELECT b <= 'aa' FROM collate2t1;
}
} {{} 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0}
do_test collate2-3.12 {
execsql {
SELECT c <= 'aa' FROM collate2t1;
}
} {{} 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1}
do_test collate2-3.13 {
execsql {
SELECT a >= 'aa' FROM collate2t1;
}
} {{} 1 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0}
do_test collate2-3.14 {
execsql {
SELECT b >= 'aa' FROM collate2t1;
}
} {{} 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
do_test collate2-3.15 {
execsql {
SELECT c >= 'aa' FROM collate2t1;
}
} {{} 1 1 1 1 0 0 0 0 0 1 0 1 0 0 0 0}
do_test collate2-3.16 {
execsql {
SELECT a BETWEEN 'Aa' AND 'Bb' FROM collate2t1;
}
} {{} 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1}
do_test collate2-3.17 {
execsql {
SELECT b BETWEEN 'Aa' AND 'Bb' FROM collate2t1;
}
} {{} 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
do_test collate2-3.18 {
execsql {
SELECT c BETWEEN 'Aa' AND 'Bb' FROM collate2t1;
}
} {{} 1 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0}
do_test collate2-3.19 {
execsql {
SELECT CASE a WHEN 'aa' THEN 1 ELSE 0 END FROM collate2t1;
}
} {0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.20 {
execsql {
SELECT CASE b WHEN 'aa' THEN 1 ELSE 0 END FROM collate2t1;
}
} {0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0}
do_test collate2-3.21 {
execsql {
SELECT CASE c WHEN 'aa' THEN 1 ELSE 0 END FROM collate2t1;
}
} {0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
ifcapable subquery {
do_test collate2-3.22 {
execsql {
SELECT a IN ('aa', 'bb') FROM collate2t1;
}
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.23 {
execsql {
SELECT b IN ('aa', 'bb') FROM collate2t1;
}
} {{} 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1}
do_test collate2-3.24 {
execsql {
SELECT c IN ('aa', 'bb') FROM collate2t1;
}
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.25 {
execsql {
SELECT a IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'))
FROM collate2t1;
}
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
do_test collate2-3.26 {
execsql {
SELECT b IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'))
FROM collate2t1;
}
} {{} 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1}
do_test collate2-3.27 {
execsql {
SELECT c IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'))
FROM collate2t1;
}
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
}
do_test collate2-4.0 {
execsql {
CREATE TABLE collate2t2(b COLLATE binary);
CREATE TABLE collate2t3(b text);
INSERT INTO collate2t2 VALUES('aa');
INSERT INTO collate2t3 VALUES('aa');
}
} {}
# Test that when both sides of a binary comparison operator have
# default collation types, the collate type for the leftmost term
# is used.
do_test collate2-4.1 {
execsql {
SELECT collate2t1.a FROM collate2t1, collate2t2
WHERE collate2t1.b = collate2t2.b;
}
} {aa aA Aa AA}
do_test collate2-4.2 {
execsql {
SELECT collate2t1.a FROM collate2t1, collate2t2
WHERE collate2t2.b = collate2t1.b;
}
} {aa}
# Test that when one side has a default collation type and the other
# does not, the collation type is used.
do_test collate2-4.3 {
execsql {
SELECT collate2t1.a FROM collate2t1, collate2t3
WHERE collate2t1.b = collate2t3.b||'';
}
} {aa aA Aa AA}
do_test collate2-4.4 {
execsql {
SELECT collate2t1.a FROM collate2t1, collate2t3
WHERE collate2t3.b||'' = collate2t1.b;
}
} {aa aA Aa AA}
do_test collate2-4.5 {
execsql {
DROP TABLE collate2t3;
}
} {}
#
# Test that the default collation types are used when the JOIN syntax
# is used in place of a WHERE clause.
#
# SQLite transforms the JOIN syntax into a WHERE clause internally, so
# the focus of these tests is to ensure that the table on the left-hand-side
# of the join determines the collation type used.
#
do_test collate2-5.0 {
execsql {
SELECT collate2t1.b FROM collate2t1 JOIN collate2t2 USING (b);
}
} {aa aA Aa AA}
do_test collate2-5.1 {
execsql {
SELECT collate2t1.b FROM collate2t2 JOIN collate2t1 USING (b);
}
} {aa}
do_test collate2-5.2 {
execsql {
SELECT collate2t1.b FROM collate2t1 NATURAL JOIN collate2t2;
}
} {aa aA Aa AA}
do_test collate2-5.3 {
execsql {
SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1;
}
} {aa}
do_test collate2-5.4 {
execsql {
SELECT collate2t2.b FROM collate2t1 LEFT OUTER JOIN collate2t2 USING (b) order by collate2t1.oid;
}
} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}}
do_test collate2-5.5 {
execsql {
SELECT collate2t1.b, collate2t2.b FROM collate2t2 LEFT OUTER JOIN collate2t1 USING (b);
}
} {aa aa}
finish_test
+429
View File
@@ -0,0 +1,429 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is page cache subsystem.
#
# $Id: collate3.test,v 1.11 2005/09/08 01:58:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
#
# Tests are organised as follows:
#
# collate3.1.* - Errors related to unknown collation sequences.
# collate3.2.* - Errors related to undefined collation sequences.
# collate3.3.* - Writing to a table that has an index with an undefined c.s.
# collate3.4.* - Misc errors.
# collate3.5.* - Collation factory.
#
#
# These tests ensure that when a user executes a statement with an
# unknown collation sequence an error is returned.
#
do_test collate3-1.0 {
execsql {
CREATE TABLE collate3t1(c1);
}
} {}
do_test collate3-1.1 {
catchsql {
SELECT * FROM collate3t1 ORDER BY 1 collate garbage;
}
} {1 {no such collation sequence: garbage}}
do_test collate3-1.2 {
catchsql {
CREATE TABLE collate3t2(c1 collate garbage);
}
} {1 {no such collation sequence: garbage}}
do_test collate3-1.3 {
catchsql {
CREATE INDEX collate3i1 ON collate3t1(c1 COLLATE garbage);
}
} {1 {no such collation sequence: garbage}}
execsql {
DROP TABLE collate3t1;
}
#
# Create a table with a default collation sequence, then close
# and re-open the database without re-registering the collation
# sequence. Then make sure the library stops us from using
# the collation sequence in:
# * an explicitly collated ORDER BY
# * an ORDER BY that uses the default collation sequence
# * an expression (=)
# * a CREATE TABLE statement
# * a CREATE INDEX statement that uses a default collation sequence
# * a GROUP BY that uses the default collation sequence
# * a SELECT DISTINCT that uses the default collation sequence
# * Compound SELECTs that uses the default collation sequence
# * An ORDER BY on a compound SELECT with an explicit ORDER BY.
#
do_test collate3-2.0 {
db collate string_compare {string compare}
execsql {
CREATE TABLE collate3t1(c1 COLLATE string_compare, c2);
}
db close
sqlite3 db test.db
expr 0
} 0
do_test collate3-2.1 {
catchsql {
SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.2 {
catchsql {
SELECT * FROM collate3t1 ORDER BY c1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.3 {
catchsql {
SELECT * FROM collate3t1 WHERE c1 = 'xxx';
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.4 {
catchsql {
CREATE TABLE collate3t2(c1 COLLATE string_compare);
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.5 {
catchsql {
CREATE INDEX collate3t1_i1 ON collate3t1(c1);
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.6 {
catchsql {
SELECT * FROM collate3t1;
}
} {0 {}}
do_test collate3-2.7.1 {
catchsql {
SELECT count(*) FROM collate3t1 GROUP BY c1;
}
} {1 {no such collation sequence: string_compare}}
# do_test collate3-2.7.2 {
# catchsql {
# SELECT * FROM collate3t1 GROUP BY c1;
# }
# } {1 {GROUP BY may only be used on aggregate queries}}
do_test collate3-2.7.2 {
catchsql {
SELECT * FROM collate3t1 GROUP BY c1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.8 {
catchsql {
SELECT DISTINCT c1 FROM collate3t1;
}
} {1 {no such collation sequence: string_compare}}
ifcapable compound {
do_test collate3-2.9 {
catchsql {
SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.10 {
catchsql {
SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.11 {
catchsql {
SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.12 {
catchsql {
SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1;
}
} {0 {}}
do_test collate3-2.13 {
btree_breakpoint
catchsql {
SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.14 {
catchsql {
SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.15 {
catchsql {
SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.16 {
catchsql {
SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-2.17 {
catchsql {
SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1;
}
} {1 {no such collation sequence: string_compare}}
} ;# ifcapable compound
#
# Create an index that uses a collation sequence then close and
# re-open the database without re-registering the collation
# sequence. Then check that for the table with the index
# * An INSERT fails,
# * An UPDATE on the column with the index fails,
# * An UPDATE on a different column succeeds.
# * A DELETE with a WHERE clause fails
# * A DELETE without a WHERE clause succeeds
#
# Also, ensure that the restrictions tested by collate3-2.* still
# apply after the index has been created.
#
do_test collate3-3.0 {
db collate string_compare {string compare}
execsql {
CREATE INDEX collate3t1_i1 ON collate3t1(c1);
INSERT INTO collate3t1 VALUES('xxx', 'yyy');
}
db close
sqlite3 db test.db
expr 0
} 0
db eval {select * from collate3t1}
do_test collate3-3.1 {
catchsql {
INSERT INTO collate3t1 VALUES('xxx', 0);
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.2 {
catchsql {
UPDATE collate3t1 SET c1 = 'xxx';
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.3 {
catchsql {
UPDATE collate3t1 SET c2 = 'xxx';
}
} {0 {}}
do_test collate3-3.4 {
catchsql {
DELETE FROM collate3t1 WHERE 1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.5 {
catchsql {
SELECT * FROM collate3t1;
}
} {0 {xxx xxx}}
do_test collate3-3.6 {
catchsql {
DELETE FROM collate3t1;
}
} {0 {}}
ifcapable {integrityck} {
do_test collate3-3.8 {
catchsql {
PRAGMA integrity_check
}
} {1 {no such collation sequence: string_compare}}
}
do_test collate3-3.9 {
catchsql {
SELECT * FROM collate3t1;
}
} {0 {}}
do_test collate3-3.10 {
catchsql {
SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.11 {
catchsql {
SELECT * FROM collate3t1 ORDER BY c1;
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.12 {
catchsql {
SELECT * FROM collate3t1 WHERE c1 = 'xxx';
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.13 {
catchsql {
CREATE TABLE collate3t2(c1 COLLATE string_compare);
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.14 {
catchsql {
CREATE INDEX collate3t1_i2 ON collate3t1(c1);
}
} {1 {no such collation sequence: string_compare}}
do_test collate3-3.15 {
execsql {
DROP TABLE collate3t1;
}
} {}
# Check we can create an index that uses an explicit collation
# sequence and then close and re-open the database.
do_test collate3-4.6 {
db collate user_defined "string compare"
execsql {
CREATE TABLE collate3t1(a, b);
INSERT INTO collate3t1 VALUES('hello', NULL);
CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined);
}
} {}
do_test collate3-4.7 {
db close
sqlite3 db test.db
catchsql {
SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
}
} {1 {no such collation sequence: user_defined}}
do_test collate3-4.8 {
db collate user_defined "string compare"
catchsql {
SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
}
} {0 {hello {}}}
do_test collate3-4.8 {
db close
lindex [catch {
sqlite3 db test.db
}] 0
} {0}
do_test collate3-4.8 {
execsql {
DROP TABLE collate3t1;
}
} {}
# Compare strings as numbers.
proc numeric_compare {lhs rhs} {
if {$rhs > $lhs} {
set res -1
} else {
set res [expr ($lhs > $rhs)?1:0]
}
return $res
}
# Check we can create a view that uses an explicit collation
# sequence and then close and re-open the database.
ifcapable view {
do_test collate3-4.9 {
db collate user_defined numeric_compare
execsql {
CREATE TABLE collate3t1(a, b);
INSERT INTO collate3t1 VALUES('2', NULL);
INSERT INTO collate3t1 VALUES('101', NULL);
INSERT INTO collate3t1 VALUES('12', NULL);
CREATE VIEW collate3v1 AS SELECT * FROM collate3t1
ORDER BY 1 COLLATE user_defined;
SELECT * FROM collate3v1;
}
} {2 {} 12 {} 101 {}}
do_test collate3-4.10 {
db close
sqlite3 db test.db
catchsql {
SELECT * FROM collate3v1;
}
} {1 {no such collation sequence: user_defined}}
do_test collate3-4.11 {
db collate user_defined numeric_compare
catchsql {
SELECT * FROM collate3v1;
}
} {0 {2 {} 12 {} 101 {}}}
do_test collate3-4.12 {
execsql {
DROP TABLE collate3t1;
}
} {}
} ;# ifcapable view
#
# Test the collation factory. In the code, the "no such collation sequence"
# message is only generated in two places. So these tests just test that
# the collation factory can be called once from each of those points.
#
do_test collate3-5.0 {
catchsql {
CREATE TABLE collate3t1(a);
INSERT INTO collate3t1 VALUES(10);
SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
}
} {1 {no such collation sequence: unk}}
do_test collate3-5.1 {
set ::cfact_cnt 0
proc cfact {nm} {
db collate $nm {string compare}
incr ::cfact_cnt
}
db collation_needed cfact
} {}
do_test collate3-5.2 {
catchsql {
SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
}
} {0 10}
do_test collate3-5.3 {
set ::cfact_cnt
} {1}
do_test collate3-5.4 {
catchsql {
SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
}
} {0 10}
do_test collate3-5.5 {
set ::cfact_cnt
} {1}
do_test collate3-5.6 {
catchsql {
SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
}
} {0 10}
do_test collate3-5.7 {
execsql {
DROP TABLE collate3t1;
CREATE TABLE collate3t1(a COLLATE unk);
}
db close
sqlite3 db test.db
catchsql {
SELECT a FROM collate3t1 ORDER BY 1;
}
} {1 {no such collation sequence: unk}}
do_test collate3-5.8 {
set ::cfact_cnt 0
proc cfact {nm} {
db collate $nm {string compare}
incr ::cfact_cnt
}
db collation_needed cfact
catchsql {
SELECT a FROM collate3t1 ORDER BY 1;
}
} {0 {}}
do_test collate3-5.9 {
execsql {
DROP TABLE collate3t1;
}
} {}
finish_test
+700
View File
@@ -0,0 +1,700 @@
#
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is page cache subsystem.
#
# $Id: collate4.test,v 1.8 2005/04/01 10:47:40 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db collate TEXT text_collate
proc text_collate {a b} {
return [string compare $a $b]
}
# Do an SQL statement. Append the search count to the end of the result.
#
proc count sql {
set ::sqlite_search_count 0
return [concat [execsql $sql] $::sqlite_search_count]
}
# This procedure executes the SQL. Then it checks the generated program
# for the SQL and appends a "nosort" to the result if the program contains the
# SortCallback opcode. If the program does not contain the SortCallback
# opcode it appends "sort"
#
proc cksort {sql} {
set ::sqlite_sort_count 0
set data [execsql $sql]
if {$::sqlite_sort_count} {set x sort} {set x nosort}
lappend data $x
return $data
}
#
# Test cases are organized roughly as follows:
#
# collate4-1.* ORDER BY.
# collate4-2.* WHERE clauses.
# collate4-3.* constraints (primary key, unique).
# collate4-4.* simple min() or max() queries.
# collate4-5.* REINDEX command
# collate4-6.* INTEGER PRIMARY KEY indices.
#
#
# These tests - collate4-1.* - check that indices are correctly
# selected or not selected to implement ORDER BY clauses when
# user defined collation sequences are involved.
#
# Because these tests also exercise all the different ways indices
# can be created, they also serve to verify that indices are correctly
# initialised with user-defined collation sequences when they are
# created.
#
# Tests named collate4-1.1.* use indices with a single column. Tests
# collate4-1.2.* use indices with two columns.
#
do_test collate4-1.1.0 {
execsql {
CREATE TABLE collate4t1(a COLLATE NOCASE, b COLLATE TEXT);
INSERT INTO collate4t1 VALUES( 'a', 'a' );
INSERT INTO collate4t1 VALUES( 'b', 'b' );
INSERT INTO collate4t1 VALUES( NULL, NULL );
INSERT INTO collate4t1 VALUES( 'B', 'B' );
INSERT INTO collate4t1 VALUES( 'A', 'A' );
CREATE INDEX collate4i1 ON collate4t1(a);
CREATE INDEX collate4i2 ON collate4t1(b);
}
} {}
do_test collate4-1.1.1 {
cksort {SELECT a FROM collate4t1 ORDER BY a}
} {{} a A b B nosort}
do_test collate4-1.1.2 {
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE NOCASE}
} {{} a A b B nosort}
do_test collate4-1.1.3 {
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE TEXT}
} {{} A B a b sort}
do_test collate4-1.1.4 {
cksort {SELECT b FROM collate4t1 ORDER BY b}
} {{} A B a b nosort}
do_test collate4-1.1.5 {
cksort {SELECT b FROM collate4t1 ORDER BY b COLLATE TEXT}
} {{} A B a b nosort}
do_test collate4-1.1.6 {
cksort {SELECT b FROM collate4t1 ORDER BY b COLLATE NOCASE}
} {{} a A b B sort}
do_test collate4-1.1.7 {
execsql {
CREATE TABLE collate4t2(
a PRIMARY KEY COLLATE NOCASE,
b UNIQUE COLLATE TEXT
);
INSERT INTO collate4t2 VALUES( 'a', 'a' );
INSERT INTO collate4t2 VALUES( NULL, NULL );
INSERT INTO collate4t2 VALUES( 'B', 'B' );
}
} {}
do_test collate4-1.1.8 {
cksort {SELECT a FROM collate4t2 ORDER BY a}
} {{} a B nosort}
do_test collate4-1.1.9 {
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE NOCASE}
} {{} a B nosort}
do_test collate4-1.1.10 {
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE TEXT}
} {{} B a sort}
do_test collate4-1.1.11 {
cksort {SELECT b FROM collate4t2 ORDER BY b}
} {{} B a nosort}
do_test collate4-1.1.12 {
cksort {SELECT b FROM collate4t2 ORDER BY b COLLATE TEXT}
} {{} B a nosort}
do_test collate4-1.1.13 {
cksort {SELECT b FROM collate4t2 ORDER BY b COLLATE NOCASE}
} {{} a B sort}
do_test collate4-1.1.14 {
execsql {
CREATE TABLE collate4t3(
b COLLATE TEXT,
a COLLATE NOCASE,
UNIQUE(a), PRIMARY KEY(b)
);
INSERT INTO collate4t3 VALUES( 'a', 'a' );
INSERT INTO collate4t3 VALUES( NULL, NULL );
INSERT INTO collate4t3 VALUES( 'B', 'B' );
}
} {}
do_test collate4-1.1.15 {
cksort {SELECT a FROM collate4t3 ORDER BY a}
} {{} a B nosort}
do_test collate4-1.1.16 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE NOCASE}
} {{} a B nosort}
do_test collate4-1.1.17 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE TEXT}
} {{} B a sort}
do_test collate4-1.1.18 {
cksort {SELECT b FROM collate4t3 ORDER BY b}
} {{} B a nosort}
do_test collate4-1.1.19 {
cksort {SELECT b FROM collate4t3 ORDER BY b COLLATE TEXT}
} {{} B a nosort}
do_test collate4-1.1.20 {
cksort {SELECT b FROM collate4t3 ORDER BY b COLLATE NOCASE}
} {{} a B sort}
do_test collate4-1.1.21 {
execsql {
CREATE TABLE collate4t4(a COLLATE NOCASE, b COLLATE TEXT);
INSERT INTO collate4t4 VALUES( 'a', 'a' );
INSERT INTO collate4t4 VALUES( 'b', 'b' );
INSERT INTO collate4t4 VALUES( NULL, NULL );
INSERT INTO collate4t4 VALUES( 'B', 'B' );
INSERT INTO collate4t4 VALUES( 'A', 'A' );
CREATE INDEX collate4i3 ON collate4t4(a COLLATE TEXT);
CREATE INDEX collate4i4 ON collate4t4(b COLLATE NOCASE);
}
} {}
do_test collate4-1.1.22 {
cksort {SELECT a FROM collate4t4 ORDER BY a}
} {{} a A b B sort}
do_test collate4-1.1.23 {
cksort {SELECT a FROM collate4t4 ORDER BY a COLLATE NOCASE}
} {{} a A b B sort}
do_test collate4-1.1.24 {
cksort {SELECT a FROM collate4t4 ORDER BY a COLLATE TEXT}
} {{} A B a b nosort}
do_test collate4-1.1.25 {
cksort {SELECT b FROM collate4t4 ORDER BY b}
} {{} A B a b sort}
do_test collate4-1.1.26 {
cksort {SELECT b FROM collate4t4 ORDER BY b COLLATE TEXT}
} {{} A B a b sort}
do_test collate4-1.1.27 {
cksort {SELECT b FROM collate4t4 ORDER BY b COLLATE NOCASE}
} {{} a A b B nosort}
do_test collate4-1.1.30 {
execsql {
DROP TABLE collate4t1;
DROP TABLE collate4t2;
DROP TABLE collate4t3;
DROP TABLE collate4t4;
}
} {}
do_test collate4-1.2.0 {
execsql {
CREATE TABLE collate4t1(a COLLATE NOCASE, b COLLATE TEXT);
INSERT INTO collate4t1 VALUES( 'a', 'a' );
INSERT INTO collate4t1 VALUES( 'b', 'b' );
INSERT INTO collate4t1 VALUES( NULL, NULL );
INSERT INTO collate4t1 VALUES( 'B', 'B' );
INSERT INTO collate4t1 VALUES( 'A', 'A' );
CREATE INDEX collate4i1 ON collate4t1(a, b);
}
} {}
do_test collate4-1.2.1 {
cksort {SELECT a FROM collate4t1 ORDER BY a}
} {{} A a B b nosort}
do_test collate4-1.2.2 {
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE nocase}
} {{} A a B b nosort}
do_test collate4-1.2.3 {
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE text}
} {{} A B a b sort}
do_test collate4-1.2.4 {
cksort {SELECT a FROM collate4t1 ORDER BY a, b}
} {{} A a B b nosort}
do_test collate4-1.2.5 {
cksort {SELECT a FROM collate4t1 ORDER BY a, b COLLATE nocase}
} {{} a A b B sort}
do_test collate4-1.2.6 {
cksort {SELECT a FROM collate4t1 ORDER BY a, b COLLATE text}
} {{} A a B b nosort}
do_test collate4-1.2.7 {
execsql {
CREATE TABLE collate4t2(
a COLLATE NOCASE,
b COLLATE TEXT,
PRIMARY KEY(a, b)
);
INSERT INTO collate4t2 VALUES( 'a', 'a' );
INSERT INTO collate4t2 VALUES( NULL, NULL );
INSERT INTO collate4t2 VALUES( 'B', 'B' );
}
} {}
do_test collate4-1.2.8 {
cksort {SELECT a FROM collate4t2 ORDER BY a}
} {{} a B nosort}
do_test collate4-1.2.9 {
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE nocase}
} {{} a B nosort}
do_test collate4-1.2.10 {
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE text}
} {{} B a sort}
do_test collate4-1.2.11 {
cksort {SELECT a FROM collate4t2 ORDER BY a, b}
} {{} a B nosort}
do_test collate4-1.2.12 {
cksort {SELECT a FROM collate4t2 ORDER BY a, b COLLATE nocase}
} {{} a B sort}
do_test collate4-1.2.13 {
cksort {SELECT a FROM collate4t2 ORDER BY a, b COLLATE text}
} {{} a B nosort}
do_test collate4-1.2.14 {
execsql {
CREATE TABLE collate4t3(a COLLATE NOCASE, b COLLATE TEXT);
INSERT INTO collate4t3 VALUES( 'a', 'a' );
INSERT INTO collate4t3 VALUES( 'b', 'b' );
INSERT INTO collate4t3 VALUES( NULL, NULL );
INSERT INTO collate4t3 VALUES( 'B', 'B' );
INSERT INTO collate4t3 VALUES( 'A', 'A' );
CREATE INDEX collate4i2 ON collate4t3(a COLLATE TEXT, b COLLATE NOCASE);
}
} {}
do_test collate4-1.2.15 {
cksort {SELECT a FROM collate4t3 ORDER BY a}
} {{} a A b B sort}
do_test collate4-1.2.16 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE nocase}
} {{} a A b B sort}
do_test collate4-1.2.17 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text}
} {{} A B a b nosort}
do_test collate4-1.2.18 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text, b}
} {{} A B a b sort}
do_test collate4-1.2.19 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text, b COLLATE nocase}
} {{} A B a b nosort}
do_test collate4-1.2.20 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text, b COLLATE text}
} {{} A B a b sort}
do_test collate4-1.2.21 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text DESC}
} {b a B A {} nosort}
do_test collate4-1.2.22 {
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text DESC, b}
} {b a B A {} sort}
do_test collate4-1.2.23 {
cksort {SELECT a FROM collate4t3
ORDER BY a COLLATE text DESC, b COLLATE nocase}
} {b a B A {} sort}
do_test collate4-1.2.24 {
cksort {SELECT a FROM collate4t3
ORDER BY a COLLATE text DESC, b COLLATE nocase DESC}
} {b a B A {} nosort}
do_test collate4-1.2.25 {
execsql {
DROP TABLE collate4t1;
DROP TABLE collate4t2;
DROP TABLE collate4t3;
}
} {}
#
# These tests - collate4-2.* - check that indices are correctly
# selected or not selected to implement WHERE clauses when user
# defined collation sequences are involved.
#
# Indices may optimise WHERE clauses using <, >, <=, >=, = or IN
# operators.
#
do_test collate4-2.1.0 {
execsql {
CREATE TABLE collate4t1(a COLLATE NOCASE);
CREATE TABLE collate4t2(b COLLATE TEXT);
INSERT INTO collate4t1 VALUES('a');
INSERT INTO collate4t1 VALUES('A');
INSERT INTO collate4t1 VALUES('b');
INSERT INTO collate4t1 VALUES('B');
INSERT INTO collate4t1 VALUES('c');
INSERT INTO collate4t1 VALUES('C');
INSERT INTO collate4t1 VALUES('d');
INSERT INTO collate4t1 VALUES('D');
INSERT INTO collate4t1 VALUES('e');
INSERT INTO collate4t1 VALUES('D');
INSERT INTO collate4t2 VALUES('A');
INSERT INTO collate4t2 VALUES('Z');
}
} {}
do_test collate4-2.1.1 {
count {
SELECT * FROM collate4t2, collate4t1 WHERE a = b;
}
} {A a A A 19}
do_test collate4-2.1.2 {
execsql {
CREATE INDEX collate4i1 ON collate4t1(a);
}
count {
SELECT * FROM collate4t2, collate4t1 WHERE a = b;
}
} {A a A A 5}
do_test collate4-2.1.3 {
count {
SELECT * FROM collate4t2, collate4t1 WHERE b = a;
}
} {A A 19}
do_test collate4-2.1.4 {
execsql {
DROP INDEX collate4i1;
CREATE INDEX collate4i1 ON collate4t1(a COLLATE TEXT);
}
count {
SELECT * FROM collate4t2, collate4t1 WHERE a = b;
}
} {A a A A 19}
do_test collate4-2.1.5 {
count {
SELECT * FROM collate4t2, collate4t1 WHERE b = a;
}
} {A A 4}
ifcapable subquery {
do_test collate4-2.1.6 {
count {
SELECT a FROM collate4t1 WHERE a IN (SELECT * FROM collate4t2);
}
} {a A 10}
do_test collate4-2.1.7 {
execsql {
DROP INDEX collate4i1;
CREATE INDEX collate4i1 ON collate4t1(a);
}
count {
SELECT a FROM collate4t1 WHERE a IN (SELECT * FROM collate4t2);
}
} {a A 6}
do_test collate4-2.1.8 {
count {
SELECT a FROM collate4t1 WHERE a IN ('z', 'a');
}
} {a A 5}
do_test collate4-2.1.9 {
execsql {
DROP INDEX collate4i1;
CREATE INDEX collate4i1 ON collate4t1(a COLLATE TEXT);
}
count {
SELECT a FROM collate4t1 WHERE a IN ('z', 'a');
}
} {a A 9}
}
do_test collate4-2.1.10 {
execsql {
DROP TABLE collate4t1;
DROP TABLE collate4t2;
}
} {}
do_test collate4-2.2.0 {
execsql {
CREATE TABLE collate4t1(a COLLATE nocase, b COLLATE text, c);
CREATE TABLE collate4t2(a COLLATE nocase, b COLLATE text, c COLLATE TEXT);
INSERT INTO collate4t1 VALUES('0', '0', '0');
INSERT INTO collate4t1 VALUES('0', '0', '1');
INSERT INTO collate4t1 VALUES('0', '1', '0');
INSERT INTO collate4t1 VALUES('0', '1', '1');
INSERT INTO collate4t1 VALUES('1', '0', '0');
INSERT INTO collate4t1 VALUES('1', '0', '1');
INSERT INTO collate4t1 VALUES('1', '1', '0');
INSERT INTO collate4t1 VALUES('1', '1', '1');
insert into collate4t2 SELECT * FROM collate4t1;
}
} {}
do_test collate4-2.2.1 {
count {
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
}
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 63}
do_test collate4-2.2.1b {
execsql {
CREATE INDEX collate4i1 ON collate4t1(a, b, c);
}
count {
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
}
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 29}
do_test collate4-2.2.2 {
execsql {
DROP INDEX collate4i1;
CREATE INDEX collate4i1 ON collate4t1(a, b, c COLLATE text);
}
count {
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
}
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 22}
do_test collate4-2.2.10 {
execsql {
DROP TABLE collate4t1;
DROP TABLE collate4t2;
}
} {}
#
# These tests - collate4-3.* verify that indices that implement
# UNIQUE and PRIMARY KEY constraints operate correctly with user
# defined collation sequences.
#
do_test collate4-3.0 {
execsql {
CREATE TABLE collate4t1(a PRIMARY KEY COLLATE NOCASE);
}
} {}
do_test collate4-3.1 {
catchsql {
INSERT INTO collate4t1 VALUES('abc');
INSERT INTO collate4t1 VALUES('ABC');
}
} {1 {column a is not unique}}
do_test collate4-3.2 {
execsql {
SELECT * FROM collate4t1;
}
} {abc}
do_test collate4-3.3 {
catchsql {
INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1;
}
} {1 {column a is not unique}}
do_test collate4-3.4 {
catchsql {
INSERT INTO collate4t1 VALUES(1);
UPDATE collate4t1 SET a = 'abc';
}
} {1 {column a is not unique}}
do_test collate4-3.5 {
execsql {
DROP TABLE collate4t1;
CREATE TABLE collate4t1(a COLLATE NOCASE UNIQUE);
}
} {}
do_test collate4-3.6 {
catchsql {
INSERT INTO collate4t1 VALUES('abc');
INSERT INTO collate4t1 VALUES('ABC');
}
} {1 {column a is not unique}}
do_test collate4-3.7 {
execsql {
SELECT * FROM collate4t1;
}
} {abc}
do_test collate4-3.8 {
catchsql {
INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1;
}
} {1 {column a is not unique}}
do_test collate4-3.9 {
catchsql {
INSERT INTO collate4t1 VALUES(1);
UPDATE collate4t1 SET a = 'abc';
}
} {1 {column a is not unique}}
do_test collate4-3.10 {
execsql {
DROP TABLE collate4t1;
CREATE TABLE collate4t1(a);
CREATE UNIQUE INDEX collate4i1 ON collate4t1(a COLLATE NOCASE);
}
} {}
do_test collate4-3.11 {
catchsql {
INSERT INTO collate4t1 VALUES('abc');
INSERT INTO collate4t1 VALUES('ABC');
}
} {1 {column a is not unique}}
do_test collate4-3.12 {
execsql {
SELECT * FROM collate4t1;
}
} {abc}
do_test collate4-3.13 {
catchsql {
INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1;
}
} {1 {column a is not unique}}
do_test collate4-3.14 {
catchsql {
INSERT INTO collate4t1 VALUES(1);
UPDATE collate4t1 SET a = 'abc';
}
} {1 {column a is not unique}}
do_test collate4-3.15 {
execsql {
DROP TABLE collate4t1;
}
} {}
# Mimic the SQLite 2 collation type NUMERIC.
db collate numeric numeric_collate
proc numeric_collate {lhs rhs} {
if {$lhs == $rhs} {return 0}
return [expr ($lhs>$rhs)?1:-1]
}
#
# These tests - collate4-4.* check that min() and max() only ever
# use indices constructed with built-in collation type numeric.
#
# CHANGED: min() and max() now use the collation type. If there
# is an indice that can be used, it is used.
#
do_test collate4-4.0 {
execsql {
CREATE TABLE collate4t1(a COLLATE TEXT);
INSERT INTO collate4t1 VALUES('2');
INSERT INTO collate4t1 VALUES('10');
INSERT INTO collate4t1 VALUES('20');
INSERT INTO collate4t1 VALUES('104');
}
} {}
do_test collate4-4.1 {
count {
SELECT max(a) FROM collate4t1
}
} {20 3}
do_test collate4-4.2 {
count {
SELECT min(a) FROM collate4t1
}
} {10 3}
do_test collate4-4.3 {
# Test that the index with collation type TEXT is used.
execsql {
CREATE INDEX collate4i1 ON collate4t1(a);
}
count {
SELECT min(a) FROM collate4t1;
}
} {10 2}
do_test collate4-4.4 {
count {
SELECT max(a) FROM collate4t1;
}
} {20 1}
do_test collate4-4.5 {
# Test that the index with collation type NUMERIC is not used.
execsql {
DROP INDEX collate4i1;
CREATE INDEX collate4i1 ON collate4t1(a COLLATE NUMERIC);
}
count {
SELECT min(a) FROM collate4t1;
}
} {10 3}
do_test collate4-4.6 {
count {
SELECT max(a) FROM collate4t1;
}
} {20 3}
do_test collate4-4.7 {
execsql {
DROP TABLE collate4t1;
}
} {}
# Also test the scalar min() and max() functions.
#
do_test collate4-4.8 {
execsql {
CREATE TABLE collate4t1(a COLLATE TEXT, b COLLATE NUMERIC);
INSERT INTO collate4t1 VALUES('11', '101');
INSERT INTO collate4t1 VALUES('101', '11')
}
} {}
do_test collate4-4.9 {
execsql {
SELECT max(a, b) FROM collate4t1;
}
} {11 11}
do_test collate4-4.10 {
execsql {
SELECT max(b, a) FROM collate4t1;
}
} {101 101}
do_test collate4-4.11 {
execsql {
SELECT max(a, '101') FROM collate4t1;
}
} {11 101}
do_test collate4-4.12 {
execsql {
SELECT max('101', a) FROM collate4t1;
}
} {11 101}
do_test collate4-4.13 {
execsql {
SELECT max(b, '101') FROM collate4t1;
}
} {101 101}
do_test collate4-4.14 {
execsql {
SELECT max('101', b) FROM collate4t1;
}
} {101 101}
do_test collate4-4.15 {
execsql {
DROP TABLE collate4t1;
}
} {}
#
# These tests - collate4.6.* - ensure that implict INTEGER PRIMARY KEY
# indices do not confuse collation sequences.
#
# These indices are never used for sorting in SQLite. And you can't
# create another index on an INTEGER PRIMARY KEY column, so we don't have
# to test that.
# (Revised 2004-Nov-22): The ROWID can be used for sorting now.
#
do_test collate4-6.0 {
execsql {
CREATE TABLE collate4t1(a INTEGER PRIMARY KEY);
INSERT INTO collate4t1 VALUES(101);
INSERT INTO collate4t1 VALUES(10);
INSERT INTO collate4t1 VALUES(15);
}
} {}
do_test collate4-6.1 {
cksort {
SELECT * FROM collate4t1 ORDER BY 1;
}
} {10 15 101 nosort}
do_test collate4-6.2 {
cksort {
SELECT * FROM collate4t1 ORDER BY oid;
}
} {10 15 101 nosort}
do_test collate4-6.3 {
cksort {
SELECT * FROM collate4t1 ORDER BY oid||'' COLLATE TEXT;
}
} {10 101 15 sort}
finish_test
+270
View File
@@ -0,0 +1,270 @@
#
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing DISTINCT, UNION, INTERSECT and EXCEPT
# SELECT statements that use user-defined collation sequences. Also
# GROUP BY clauses that use user-defined collation sequences.
#
# $Id: collate5.test,v 1.5 2005/09/07 22:48:16 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
#
# Tests are organised as follows:
# collate5-1.* - DISTINCT
# collate5-2.* - Compound SELECT
# collate5-3.* - ORDER BY on compound SELECT
# collate5-4.* - GROUP BY
# Create the collation sequence 'TEXT', purely for asthetic reasons. The
# test cases in this script could just as easily use BINARY.
db collate TEXT [list string compare]
# Mimic the SQLite 2 collation type NUMERIC.
db collate numeric numeric_collate
proc numeric_collate {lhs rhs} {
if {$lhs == $rhs} {return 0}
return [expr ($lhs>$rhs)?1:-1]
}
#
# These tests - collate5-1.* - focus on the DISTINCT keyword.
#
do_test collate5-1.0 {
execsql {
CREATE TABLE collate5t1(a COLLATE nocase, b COLLATE text);
INSERT INTO collate5t1 VALUES('a', 'apple');
INSERT INTO collate5t1 VALUES('A', 'Apple');
INSERT INTO collate5t1 VALUES('b', 'banana');
INSERT INTO collate5t1 VALUES('B', 'banana');
INSERT INTO collate5t1 VALUES('n', NULL);
INSERT INTO collate5t1 VALUES('N', NULL);
}
} {}
do_test collate5-1.1 {
execsql {
SELECT DISTINCT a FROM collate5t1;
}
} {a b n}
do_test collate5-1.2 {
execsql {
SELECT DISTINCT b FROM collate5t1;
}
} {apple Apple banana {}}
do_test collate5-1.3 {
execsql {
SELECT DISTINCT a, b FROM collate5t1;
}
} {a apple A Apple b banana n {}}
# The remainder of this file tests compound SELECT statements.
# Omit it if the library is compiled such that they are omitted.
#
ifcapable !compound {
finish_test
return
}
#
# Tests named collate5-2.* focus on UNION, EXCEPT and INTERSECT
# queries that use user-defined collation sequences.
#
# collate5-2.1.* - UNION
# collate5-2.2.* - INTERSECT
# collate5-2.3.* - EXCEPT
#
do_test collate5-2.0 {
execsql {
CREATE TABLE collate5t2(a COLLATE text, b COLLATE nocase);
INSERT INTO collate5t2 VALUES('a', 'apple');
INSERT INTO collate5t2 VALUES('A', 'apple');
INSERT INTO collate5t2 VALUES('b', 'banana');
INSERT INTO collate5t2 VALUES('B', 'Banana');
}
} {}
do_test collate5-2.1.1 {
execsql {
SELECT a FROM collate5t1 UNION select a FROM collate5t2;
}
} {A B N}
do_test collate5-2.1.2 {
execsql {
SELECT a FROM collate5t2 UNION select a FROM collate5t1;
}
} {A B N a b n}
do_test collate5-2.1.3 {
execsql {
SELECT a, b FROM collate5t1 UNION select a, b FROM collate5t2;
}
} {A Apple A apple B Banana b banana N {}}
do_test collate5-2.1.4 {
execsql {
SELECT a, b FROM collate5t2 UNION select a, b FROM collate5t1;
}
} {A Apple B banana N {} a apple b banana n {}}
do_test collate5-2.2.1 {
execsql {
SELECT a FROM collate5t1 EXCEPT select a FROM collate5t2;
}
} {N}
do_test collate5-2.2.2 {
execsql {
SELECT a FROM collate5t2 EXCEPT select a FROM collate5t1 WHERE a != 'a';
}
} {A a}
do_test collate5-2.2.3 {
execsql {
SELECT a, b FROM collate5t1 EXCEPT select a, b FROM collate5t2;
}
} {A Apple N {}}
do_test collate5-2.2.4 {
execsql {
SELECT a, b FROM collate5t2 EXCEPT select a, b FROM collate5t1
where a != 'a';
}
} {A apple a apple}
do_test collate5-2.3.1 {
execsql {
SELECT a FROM collate5t1 INTERSECT select a FROM collate5t2;
}
} {A B}
do_test collate5-2.3.2 {
execsql {
SELECT a FROM collate5t2 INTERSECT select a FROM collate5t1 WHERE a != 'a';
}
} {B b}
do_test collate5-2.3.3 {
execsql {
SELECT a, b FROM collate5t1 INTERSECT select a, b FROM collate5t2;
}
} {a apple B banana}
do_test collate5-2.3.4 {
execsql {
SELECT a, b FROM collate5t2 INTERSECT select a, b FROM collate5t1;
}
} {A apple B Banana a apple b banana}
#
# This test ensures performs a UNION operation with a bunch of different
# length records. The goal is to test that the logic that compares records
# for the compound SELECT operators works with record lengths that lie
# either side of the troublesome 256 and 65536 byte marks.
#
set ::lens [list \
0 1 2 3 4 5 6 7 8 9 \
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 \
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 \
65520 65521 65522 65523 65524 65525 65526 65527 65528 65529 65530 \
65531 65532 65533 65534 65535 65536 65537 65538 65539 65540 65541 \
65542 65543 65544 65545 65546 65547 65548 65549 65550 65551 ]
do_test collate5-2.4.0 {
execsql {
BEGIN;
CREATE TABLE collate5t3(a, b);
}
foreach ii $::lens {
execsql "INSERT INTO collate5t3 VALUES($ii, '[string repeat a $ii]');"
}
expr [llength [execsql {
COMMIT;
SELECT * FROM collate5t3 UNION SELECT * FROM collate5t3;
}]] / 2
} [llength $::lens]
do_test collate5-2.4.1 {
execsql {DROP TABLE collate5t3;}
} {}
unset ::lens
#
# These tests - collate5-3.* - focus on compound SELECT queries that
# feature ORDER BY clauses.
#
do_test collate5-3.0 {
execsql {
SELECT a FROM collate5t1 UNION ALL SELECT a FROM collate5t2 ORDER BY 1;
}
} {a A a A b B b B n N}
do_test collate5-3.1 {
execsql {
SELECT a FROM collate5t2 UNION ALL SELECT a FROM collate5t1 ORDER BY 1;
}
} {A A B B N a a b b n}
do_test collate5-3.2 {
execsql {
SELECT a FROM collate5t1 UNION ALL SELECT a FROM collate5t2
ORDER BY 1 COLLATE TEXT;
}
} {A A B B N a a b b n}
do_test collate5-3.3 {
execsql {
CREATE TABLE collate5t_cn(a COLLATE NUMERIC);
CREATE TABLE collate5t_ct(a COLLATE TEXT);
INSERT INTO collate5t_cn VALUES('1');
INSERT INTO collate5t_cn VALUES('11');
INSERT INTO collate5t_cn VALUES('101');
INSERT INTO collate5t_ct SELECT * FROM collate5t_cn;
}
} {}
do_test collate5-3.4 {
execsql {
SELECT a FROM collate5t_cn INTERSECT SELECT a FROM collate5t_ct ORDER BY 1;
}
} {1 11 101}
do_test collate5-3.5 {
execsql {
SELECT a FROM collate5t_ct INTERSECT SELECT a FROM collate5t_cn ORDER BY 1;
}
} {1 101 11}
do_test collate5-3.20 {
execsql {
DROP TABLE collate5t_cn;
DROP TABLE collate5t_ct;
DROP TABLE collate5t1;
DROP TABLE collate5t2;
}
} {}
do_test collate5-4.0 {
execsql {
CREATE TABLE collate5t1(a COLLATE NOCASE, b COLLATE NUMERIC);
INSERT INTO collate5t1 VALUES('a', '1');
INSERT INTO collate5t1 VALUES('A', '1.0');
INSERT INTO collate5t1 VALUES('b', '2');
INSERT INTO collate5t1 VALUES('B', '3');
}
} {}
do_test collate5-4.1 {
string tolower [execsql {
SELECT a, count(*) FROM collate5t1 GROUP BY a;
}]
} {a 2 b 2}
do_test collate5-4.2 {
execsql {
SELECT a, b, count(*) FROM collate5t1 GROUP BY a, b ORDER BY a, b;
}
} {A 1.0 2 b 2 1 B 3 1}
do_test collate5-4.3 {
execsql {
DROP TABLE collate5t1;
}
} {}
finish_test
+111
View File
@@ -0,0 +1,111 @@
#
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is collation sequences in concert with triggers.
#
# $Id: collate6.test,v 1.2 2004/11/04 04:42:28 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# There are no tests in this file that will work without
# trigger support.
#
ifcapable {!trigger} {
finish_test
return
}
# Create a case-insensitive collation type NOCASE for use in testing.
# Normally, capital letters are less than their lower-case counterparts.
db collate NOCASE nocase_collate
proc nocase_collate {a b} {
return [string compare -nocase $a $b]
}
#
# Tests are organized as follows:
# collate6-1.* - triggers.
#
do_test collate6-1.0 {
execsql {
CREATE TABLE collate6log(a, b);
CREATE TABLE collate6tab(a COLLATE NOCASE, b COLLATE BINARY);
}
} {}
# Test that the default collation sequence applies to new.* references
# in WHEN clauses.
do_test collate6-1.1 {
execsql {
CREATE TRIGGER collate6trig BEFORE INSERT ON collate6tab
WHEN new.a = 'a' BEGIN
INSERT INTO collate6log VALUES(new.a, new.b);
END;
}
} {}
do_test collate6-1.2 {
execsql {
INSERT INTO collate6tab VALUES('a', 'b');
SELECT * FROM collate6log;
}
} {a b}
do_test collate6-1.3 {
execsql {
INSERT INTO collate6tab VALUES('A', 'B');
SELECT * FROM collate6log;
}
} {a b A B}
do_test collate6-1.4 {
execsql {
DROP TRIGGER collate6trig;
DELETE FROM collate6log;
}
} {}
# Test that the default collation sequence applies to new.* references
# in the body of triggers.
do_test collate6-1.5 {
execsql {
CREATE TRIGGER collate6trig BEFORE INSERT ON collate6tab BEGIN
INSERT INTO collate6log VALUES(new.a='a', new.b='b');
END;
}
} {}
do_test collate6-1.6 {
execsql {
INSERT INTO collate6tab VALUES('a', 'b');
SELECT * FROM collate6log;
}
} {1 1}
do_test collate6-1.7 {
execsql {
INSERT INTO collate6tab VALUES('A', 'B');
SELECT * FROM collate6log;
}
} {1 1 1 0}
do_test collate6-1.8 {
execsql {
DROP TRIGGER collate6trig;
DELETE FROM collate6log;
}
} {}
do_test collate6-1.9 {
execsql {
DROP TABLE collate6tab;
}
} {}
finish_test
+103
View File
@@ -0,0 +1,103 @@
#
# 2006 February 9
#
# 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 regression tests for SQLite library. The
# focus of this script is the sqlite3_table_column_metadata() API.
#
# $Id: colmeta.test,v 1.3 2006/02/10 13:33:31 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !columnmetadata {
finish_test
return
}
# Set up a schema in the main and temp test databases.
do_test colmeta-0 {
execsql {
CREATE TABLE abc(a, b, c);
CREATE TABLE abc2(a PRIMARY KEY COLLATE NOCASE, b VARCHAR(32), c);
CREATE TABLE abc3(a NOT NULL, b INTEGER PRIMARY KEY, c);
}
ifcapable autoinc {
execsql {
CREATE TABLE abc4(a, b INTEGER PRIMARY KEY AUTOINCREMENT, c);
}
}
ifcapable view {
execsql {
CREATE VIEW v1 AS SELECT * FROM abc2;
}
}
} {}
# Return values are of the form:
#
# {<decl-type> <collation> <not null> <primary key> <auto increment>}
#
set tests {
1 {main abc a} {0 {{} BINARY 0 0 0}}
2 {{} abc a} {0 {{} BINARY 0 0 0}}
3 {{} abc2 b} {0 {VARCHAR(32) BINARY 0 0 0}}
4 {main abc2 b} {0 {VARCHAR(32) BINARY 0 0 0}}
5 {{} abc2 a} {0 {{} NOCASE 0 1 0}}
6 {{} abc3 a} {0 {{} BINARY 1 0 0}}
7 {{} abc3 b} {0 {INTEGER BINARY 0 1 0}}
13 {main abc rowid} {0 {INTEGER BINARY 0 1 0}}
14 {main abc3 rowid} {0 {INTEGER BINARY 0 1 0}}
16 {main abc d} {1 {no such table column: abc.d}}
}
ifcapable view {
set tests [concat $tests {
8 {{} abc4 b} {0 {INTEGER BINARY 0 1 1}}
15 {main abc4 rowid} {0 {INTEGER BINARY 0 1 1}}
}]
}
ifcapable view {
set tests [concat $tests {
9 {{} v1 a} {1 {no such table column: v1.a}}
10 {main v1 b} {1 {no such table column: v1.b}}
11 {main v1 badname} {1 {no such table column: v1.badname}}
12 {main v1 rowid} {1 {no such table column: v1.rowid}}
}]
}
foreach {tn params results} $tests {
set ::DB [sqlite3_connection_pointer db]
set tstbody [concat sqlite3_table_column_metadata $::DB $params]
do_test colmeta-$tn.1 {
list [catch $tstbody msg] [set msg]
} $results
db close
sqlite3 db test.db
set ::DB [sqlite3_connection_pointer db]
set tstbody [concat sqlite3_table_column_metadata $::DB $params]
do_test colmeta-$tn.2 {
list [catch $tstbody msg] [set msg]
} $results
}
do_test colmeta-misuse.1 {
db close
set rc [catch {
sqlite3_table_column_metadata $::DB a b c
} msg]
list $rc $msg
} {1 {library routine called out of sequence}}
finish_test
+754
View File
@@ -0,0 +1,754 @@
# 2002 January 29
#
# 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 regression tests for SQLite library.
#
# This file implements tests for the conflict resolution extension
# to SQLite.
#
# $Id: conflict.test,v 1.27 2006/01/17 09:35:02 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !conflict {
finish_test
return
}
# Create tables for the first group of tests.
#
do_test conflict-1.0 {
execsql {
CREATE TABLE t1(a, b, c, UNIQUE(a,b));
CREATE TABLE t2(x);
SELECT c FROM t1 ORDER BY c;
}
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
# t3 Number of temporary files created by this test
#
foreach {i cmd t0 t1 t2 t3} {
1 INSERT 1 {} 1 0
2 {INSERT OR IGNORE} 0 3 1 0
3 {INSERT OR REPLACE} 0 4 1 0
4 REPLACE 0 4 1 0
5 {INSERT OR FAIL} 1 {} 1 0
6 {INSERT OR ABORT} 1 {} 1 0
7 {INSERT OR ROLLBACK} 1 {} {} 0
} {
do_test conflict-1.$i {
set ::sqlite_opentemp_count 0
set r0 [catch {execsql [subst {
DELETE FROM t1;
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
BEGIN;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
catch {execsql {COMMIT}}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
set r3 $::sqlite_opentemp_count
list $r0 $r1 $r2 $r3
} [list $t0 $t1 $t2 $t3]
}
# Create tables for the first group of tests.
#
do_test conflict-2.0 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(a,b));
CREATE TABLE t2(x);
SELECT c FROM t1 ORDER BY c;
}
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i cmd t0 t1 t2} {
1 INSERT 1 {} 1
2 {INSERT OR IGNORE} 0 3 1
3 {INSERT OR REPLACE} 0 4 1
4 REPLACE 0 4 1
5 {INSERT OR FAIL} 1 {} 1
6 {INSERT OR ABORT} 1 {} 1
7 {INSERT OR ROLLBACK} 1 {} {}
} {
do_test conflict-2.$i {
set r0 [catch {execsql [subst {
DELETE FROM t1;
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
BEGIN;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
catch {execsql {COMMIT}}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
# Create tables for the first group of tests.
#
do_test conflict-3.0 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a, b, c INTEGER, PRIMARY KEY(c), UNIQUE(a,b));
CREATE TABLE t2(x);
SELECT c FROM t1 ORDER BY c;
}
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i cmd t0 t1 t2} {
1 INSERT 1 {} 1
2 {INSERT OR IGNORE} 0 3 1
3 {INSERT OR REPLACE} 0 4 1
4 REPLACE 0 4 1
5 {INSERT OR FAIL} 1 {} 1
6 {INSERT OR ABORT} 1 {} 1
7 {INSERT OR ROLLBACK} 1 {} {}
} {
do_test conflict-3.$i {
set r0 [catch {execsql [subst {
DELETE FROM t1;
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
BEGIN;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
catch {execsql {COMMIT}}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-4.0 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(x);
SELECT x FROM t2;
}
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf1 The conflict resolution algorithm on the UNIQUE constraint
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf1 cmd t0 t1 t2} {
1 {} INSERT 1 {} 1
2 REPLACE INSERT 0 4 1
3 IGNORE INSERT 0 3 1
4 FAIL INSERT 1 {} 1
5 ABORT INSERT 1 {} 1
6 ROLLBACK INSERT 1 {} {}
7 REPLACE {INSERT OR IGNORE} 0 3 1
8 IGNORE {INSERT OR REPLACE} 0 4 1
9 FAIL {INSERT OR IGNORE} 0 3 1
10 ABORT {INSERT OR REPLACE} 0 4 1
11 ROLLBACK {INSERT OR IGNORE } 0 3 1
} {
do_test conflict-4.$i {
if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
set r0 [catch {execsql [subst {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,UNIQUE(a,b) $conf1);
DELETE FROM t2;
INSERT INTO t1 VALUES(1,2,3);
BEGIN;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,4);
}]} r1]
catch {execsql {COMMIT}}
if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-5.0 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(x);
SELECT x FROM t2;
}
} {}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf1 The conflict resolution algorithm on the NOT NULL constraint
# cmd An INSERT or REPLACE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "c" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t2
#
foreach {i conf1 cmd t0 t1 t2} {
1 {} INSERT 1 {} 1
2 REPLACE INSERT 0 5 1
3 IGNORE INSERT 0 {} 1
4 FAIL INSERT 1 {} 1
5 ABORT INSERT 1 {} 1
6 ROLLBACK INSERT 1 {} {}
7 REPLACE {INSERT OR IGNORE} 0 {} 1
8 IGNORE {INSERT OR REPLACE} 0 5 1
9 FAIL {INSERT OR IGNORE} 0 {} 1
10 ABORT {INSERT OR REPLACE} 0 5 1
11 ROLLBACK {INSERT OR IGNORE} 0 {} 1
12 {} {INSERT OR IGNORE} 0 {} 1
13 {} {INSERT OR REPLACE} 0 5 1
14 {} {INSERT OR FAIL} 1 {} 1
15 {} {INSERT OR ABORT} 1 {} 1
16 {} {INSERT OR ROLLBACK} 1 {} {}
} {
if {$t0} {set t1 {t1.c may not be NULL}}
do_test conflict-5.$i {
if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
set r0 [catch {execsql [subst {
DROP TABLE t1;
CREATE TABLE t1(a,b,c NOT NULL $conf1 DEFAULT 5);
DELETE FROM t2;
BEGIN;
INSERT INTO t2 VALUES(1);
$cmd INTO t1 VALUES(1,2,NULL);
}]} r1]
catch {execsql {COMMIT}}
if {!$r0} {set r1 [execsql {SELECT c FROM t1}]}
set r2 [execsql {SELECT x FROM t2}]
list $r0 $r1 $r2
} [list $t0 $t1 $t2]
}
do_test conflict-6.0 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(a,b,c);
INSERT INTO t2 VALUES(1,2,1);
INSERT INTO t2 VALUES(2,3,2);
INSERT INTO t2 VALUES(3,4,1);
INSERT INTO t2 VALUES(4,5,4);
SELECT c FROM t2 ORDER BY b;
CREATE TABLE t3(x);
INSERT INTO t3 VALUES(1);
}
} {1 2 1 4}
# Six columns of configuration data as follows:
#
# i The reference number of the test
# conf1 The conflict resolution algorithm on the UNIQUE constraint
# cmd An UPDATE command to execute against table t1
# t0 True if there is an error from $cmd
# t1 Content of "b" column of t1 assuming no error in $cmd
# t2 Content of "x" column of t3
# t3 Number of temporary files created
#
foreach {i conf1 cmd t0 t1 t2 t3} {
1 {} UPDATE 1 {6 7 8 9} 1 1
2 REPLACE UPDATE 0 {7 6 9} 1 1
3 IGNORE UPDATE 0 {6 7 3 9} 1 1
4 FAIL UPDATE 1 {6 7 3 4} 1 0
5 ABORT UPDATE 1 {1 2 3 4} 1 1
6 ROLLBACK UPDATE 1 {1 2 3 4} 0 0
7 REPLACE {UPDATE OR IGNORE} 0 {6 7 3 9} 1 1
8 IGNORE {UPDATE OR REPLACE} 0 {7 6 9} 1 1
9 FAIL {UPDATE OR IGNORE} 0 {6 7 3 9} 1 1
10 ABORT {UPDATE OR REPLACE} 0 {7 6 9} 1 1
11 ROLLBACK {UPDATE OR IGNORE} 0 {6 7 3 9} 1 1
12 {} {UPDATE OR IGNORE} 0 {6 7 3 9} 1 1
13 {} {UPDATE OR REPLACE} 0 {7 6 9} 1 1
14 {} {UPDATE OR FAIL} 1 {6 7 3 4} 1 0
15 {} {UPDATE OR ABORT} 1 {1 2 3 4} 1 1
16 {} {UPDATE OR ROLLBACK} 1 {1 2 3 4} 0 0
} {
if {$t0} {set t1 {column a is not unique}}
do_test conflict-6.$i {
db close
sqlite3 db test.db
if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"}
execsql {pragma temp_store=file}
set ::sqlite_opentemp_count 0
set r0 [catch {execsql [subst {
DROP TABLE t1;
CREATE TABLE t1(a,b,c, UNIQUE(a) $conf1);
INSERT INTO t1 SELECT * FROM t2;
UPDATE t3 SET x=0;
BEGIN;
$cmd t3 SET x=1;
$cmd t1 SET b=b*2;
$cmd t1 SET a=c+5;
}]} r1]
catch {execsql {COMMIT}}
if {!$r0} {set r1 [execsql {SELECT a FROM t1 ORDER BY b}]}
set r2 [execsql {SELECT x FROM t3}]
list $r0 $r1 $r2 $::sqlite_opentemp_count
} [list $t0 $t1 $t2 $t3]
}
# Test to make sure a lot of IGNOREs don't cause a stack overflow
#
do_test conflict-7.1 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
CREATE TABLE t1(a unique, b);
}
for {set i 1} {$i<=50} {incr i} {
execsql "INSERT into t1 values($i,[expr {$i+1}]);"
}
execsql {
SELECT count(*), min(a), max(b) FROM t1;
}
} {50 1 51}
do_test conflict-7.2 {
execsql {
PRAGMA count_changes=on;
UPDATE OR IGNORE t1 SET a=1000;
}
} {1}
do_test conflict-7.2.1 {
db changes
} {1}
do_test conflict-7.3 {
execsql {
SELECT b FROM t1 WHERE a=1000;
}
} {2}
do_test conflict-7.4 {
execsql {
SELECT count(*) FROM t1;
}
} {50}
do_test conflict-7.5 {
execsql {
PRAGMA count_changes=on;
UPDATE OR REPLACE t1 SET a=1001;
}
} {50}
do_test conflict-7.5.1 {
db changes
} {50}
do_test conflict-7.6 {
execsql {
SELECT b FROM t1 WHERE a=1001;
}
} {51}
do_test conflict-7.7 {
execsql {
SELECT count(*) FROM t1;
}
} {1}
# Update for version 3: A SELECT statement no longer resets the change
# counter (Test result changes from 0 to 50).
do_test conflict-7.7.1 {
db changes
} {50}
# Make sure the row count is right for rows that are ignored on
# an insert.
#
do_test conflict-8.1 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES(1,2);
}
execsql {
INSERT OR IGNORE INTO t1 VALUES(2,3);
}
} {1}
do_test conflict-8.1.1 {
db changes
} {1}
do_test conflict-8.2 {
execsql {
INSERT OR IGNORE INTO t1 VALUES(2,4);
}
} {0}
do_test conflict-8.2.1 {
db changes
} {0}
do_test conflict-8.3 {
execsql {
INSERT OR REPLACE INTO t1 VALUES(2,4);
}
} {1}
do_test conflict-8.3.1 {
db changes
} {1}
do_test conflict-8.4 {
execsql {
INSERT OR IGNORE INTO t1 SELECT * FROM t1;
}
} {0}
do_test conflict-8.4.1 {
db changes
} {0}
do_test conflict-8.5 {
execsql {
INSERT OR IGNORE INTO t1 SELECT a+2,b+2 FROM t1;
}
} {2}
do_test conflict-8.5.1 {
db changes
} {2}
do_test conflict-8.6 {
execsql {
INSERT OR IGNORE INTO t1 SELECT a+3,b+3 FROM t1;
}
} {3}
do_test conflict-8.6.1 {
db changes
} {3}
integrity_check conflict-8.99
do_test conflict-9.1 {
execsql {
PRAGMA count_changes=0;
CREATE TABLE t2(
a INTEGER UNIQUE ON CONFLICT IGNORE,
b INTEGER UNIQUE ON CONFLICT FAIL,
c INTEGER UNIQUE ON CONFLICT REPLACE,
d INTEGER UNIQUE ON CONFLICT ABORT,
e INTEGER UNIQUE ON CONFLICT ROLLBACK
);
CREATE TABLE t3(x);
INSERT INTO t3 VALUES(1);
SELECT * FROM t3;
}
} {1}
do_test conflict-9.2 {
catchsql {
INSERT INTO t2 VALUES(1,1,1,1,1);
INSERT INTO t2 VALUES(2,2,2,2,2);
SELECT * FROM t2;
}
} {0 {1 1 1 1 1 2 2 2 2 2}}
do_test conflict-9.3 {
catchsql {
INSERT INTO t2 VALUES(1,3,3,3,3);
SELECT * FROM t2;
}
} {0 {1 1 1 1 1 2 2 2 2 2}}
do_test conflict-9.4 {
catchsql {
UPDATE t2 SET a=a+1 WHERE a=1;
SELECT * FROM t2;
}
} {0 {1 1 1 1 1 2 2 2 2 2}}
do_test conflict-9.5 {
catchsql {
INSERT INTO t2 VALUES(3,1,3,3,3);
SELECT * FROM t2;
}
} {1 {column b is not unique}}
do_test conflict-9.6 {
catchsql {
UPDATE t2 SET b=b+1 WHERE b=1;
SELECT * FROM t2;
}
} {1 {column b is not unique}}
do_test conflict-9.7 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
INSERT INTO t2 VALUES(3,1,3,3,3);
SELECT * FROM t2;
}
} {1 {column b is not unique}}
do_test conflict-9.8 {
execsql {COMMIT}
execsql {SELECT * FROM t3}
} {2}
do_test conflict-9.9 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
UPDATE t2 SET b=b+1 WHERE b=1;
SELECT * FROM t2;
}
} {1 {column b is not unique}}
do_test conflict-9.10 {
execsql {COMMIT}
execsql {SELECT * FROM t3}
} {3}
do_test conflict-9.11 {
catchsql {
INSERT INTO t2 VALUES(3,3,3,1,3);
SELECT * FROM t2;
}
} {1 {column d is not unique}}
do_test conflict-9.12 {
catchsql {
UPDATE t2 SET d=d+1 WHERE d=1;
SELECT * FROM t2;
}
} {1 {column d is not unique}}
do_test conflict-9.13 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
INSERT INTO t2 VALUES(3,3,3,1,3);
SELECT * FROM t2;
}
} {1 {column d is not unique}}
do_test conflict-9.14 {
execsql {COMMIT}
execsql {SELECT * FROM t3}
} {4}
do_test conflict-9.15 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
UPDATE t2 SET d=d+1 WHERE d=1;
SELECT * FROM t2;
}
} {1 {column d is not unique}}
do_test conflict-9.16 {
execsql {COMMIT}
execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.17 {
catchsql {
INSERT INTO t2 VALUES(3,3,3,3,1);
SELECT * FROM t2;
}
} {1 {column e is not unique}}
do_test conflict-9.18 {
catchsql {
UPDATE t2 SET e=e+1 WHERE e=1;
SELECT * FROM t2;
}
} {1 {column e is not unique}}
do_test conflict-9.19 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
INSERT INTO t2 VALUES(3,3,3,3,1);
SELECT * FROM t2;
}
} {1 {column e is not unique}}
do_test conflict-9.20 {
catch {execsql {COMMIT}}
execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.21 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
UPDATE t2 SET e=e+1 WHERE e=1;
SELECT * FROM t2;
}
} {1 {column e is not unique}}
do_test conflict-9.22 {
catch {execsql {COMMIT}}
execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.23 {
catchsql {
INSERT INTO t2 VALUES(3,3,1,3,3);
SELECT * FROM t2;
}
} {0 {2 2 2 2 2 3 3 1 3 3}}
do_test conflict-9.24 {
catchsql {
UPDATE t2 SET c=c-1 WHERE c=2;
SELECT * FROM t2;
}
} {0 {2 2 1 2 2}}
do_test conflict-9.25 {
catchsql {
BEGIN;
UPDATE t3 SET x=x+1;
INSERT INTO t2 VALUES(3,3,1,3,3);
SELECT * FROM t2;
}
} {0 {3 3 1 3 3}}
do_test conflict-9.26 {
catch {execsql {COMMIT}}
execsql {SELECT * FROM t3}
} {6}
do_test conflict-10.1 {
catchsql {
DELETE FROM t1;
BEGIN;
INSERT OR ROLLBACK INTO t1 VALUES(1,2);
INSERT OR ROLLBACK INTO t1 VALUES(1,3);
COMMIT;
}
execsql {SELECT * FROM t1}
} {}
do_test conflict-10.2 {
catchsql {
CREATE TABLE t4(x);
CREATE UNIQUE INDEX t4x ON t4(x);
BEGIN;
INSERT OR ROLLBACK INTO t4 VALUES(1);
INSERT OR ROLLBACK INTO t4 VALUES(1);
COMMIT;
}
execsql {SELECT * FROM t4}
} {}
# Ticket #1171. Make sure statement rollbacks do not
# damage the database.
#
do_test conflict-11.1 {
execsql {
-- Create a database object (pages 2, 3 of the file)
BEGIN;
CREATE TABLE abc(a UNIQUE, b, c);
INSERT INTO abc VALUES(1, 2, 3);
INSERT INTO abc VALUES(4, 5, 6);
INSERT INTO abc VALUES(7, 8, 9);
COMMIT;
}
# Set a small cache size so that changes will spill into
# the database file.
execsql {
PRAGMA cache_size = 10;
}
# Make lots of changes. Because of the small cache, some
# (most?) of these changes will spill into the disk file.
# In other words, some of the changes will not be held in
# cache.
#
execsql {
BEGIN;
-- Make sure the pager is in EXCLUSIVE state.
CREATE TABLE def(d, e, f);
INSERT INTO def VALUES
('xxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzz');
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
DELETE FROM abc WHERE a = 4;
}
# Execute a statement that does a statement rollback due to
# a constraint failure.
#
catchsql {
INSERT INTO abc SELECT 10, 20, 30 FROM def;
}
# Rollback the database. Verify that the state of the ABC table
# is unchanged from the beginning of the transaction. In other words,
# make sure the DELETE on table ABC that occurred within the transaction
# had no effect.
#
execsql {
ROLLBACK;
SELECT * FROM abc;
}
} {1 2 3 4 5 6 7 8 9}
integrity_check conflict-11.2
# Repeat test conflict-11.1 but this time commit.
#
do_test conflict-11.3 {
execsql {
BEGIN;
-- Make sure the pager is in EXCLUSIVE state.
UPDATE abc SET a=a+1;
CREATE TABLE def(d, e, f);
INSERT INTO def VALUES
('xxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzz');
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
DELETE FROM abc WHERE a = 4;
}
catchsql {
INSERT INTO abc SELECT 10, 20, 30 FROM def;
}
execsql {
ROLLBACK;
SELECT * FROM abc;
}
} {1 2 3 4 5 6 7 8 9}
# Repeat test conflict-11.1 but this time commit.
#
do_test conflict-11.5 {
execsql {
BEGIN;
-- Make sure the pager is in EXCLUSIVE state.
CREATE TABLE def(d, e, f);
INSERT INTO def VALUES
('xxxxxxxxxxxxxxx', 'yyyyyyyyyyyyyyyy', 'zzzzzzzzzzzzzzzz');
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
INSERT INTO def SELECT * FROM def;
DELETE FROM abc WHERE a = 4;
}
catchsql {
INSERT INTO abc SELECT 10, 20, 30 FROM def;
}
execsql {
COMMIT;
SELECT * FROM abc;
}
} {1 2 3 7 8 9}
integrity_check conflict-11.6
finish_test
+169
View File
@@ -0,0 +1,169 @@
# 2004 August 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 regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt.test,v 1.8 2005/02/19 08:18:06 danielk1977 Exp $
catch {file delete -force test.db}
catch {file delete -force test.db-journal}
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Construct a large database for testing.
#
do_test corrupt-1.1 {
execsql {
BEGIN;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(randstr(100,100));
INSERT INTO t1 VALUES(randstr(90,90));
INSERT INTO t1 VALUES(randstr(80,80));
INSERT INTO t1 SELECT x || randstr(5,5) FROM t1;
INSERT INTO t1 SELECT x || randstr(6,6) FROM t1;
INSERT INTO t1 SELECT x || randstr(7,7) FROM t1;
INSERT INTO t1 SELECT x || randstr(8,8) FROM t1;
INSERT INTO t1 VALUES(randstr(3000,3000));
INSERT INTO t1 SELECT x || randstr(9,9) FROM t1;
INSERT INTO t1 SELECT x || randstr(10,10) FROM t1;
INSERT INTO t1 SELECT x || randstr(11,11) FROM t1;
INSERT INTO t1 SELECT x || randstr(12,12) FROM t1;
CREATE INDEX t1i1 ON t1(x);
CREATE TABLE t2 AS SELECT * FROM t1;
DELETE FROM t2 WHERE rowid%5!=0;
COMMIT;
}
} {}
integrity_check corrupt-1.2
# Copy file $from into $to
#
proc copy_file {from to} {
set f [open $from]
fconfigure $f -translation binary
set t [open $to w]
fconfigure $t -translation binary
puts -nonewline $t [read $f [file size $from]]
close $t
close $f
}
# Setup for the tests. Make a backup copy of the good database in test.bu.
# Create a string of garbage data that is 256 bytes long.
#
copy_file test.db test.bu
set fsize [file size test.db]
set junk "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
while {[string length $junk]<256} {append junk $junk}
set junk [string range $junk 0 255]
# Go through the database and write garbage data into each 256 segment
# of the file. Then do various operations on the file to make sure that
# the database engine can recover gracefully from the corruption.
#
for {set i [expr {1*256}]} {$i<$fsize-256} {incr i 256} {
set tn [expr {$i/256}]
db close
copy_file test.bu test.db
set fd [open test.db r+]
fconfigure $fd -translation binary
seek $fd $i
puts -nonewline $fd $junk
close $fd
do_test corrupt-2.$tn.1 {
sqlite3 db test.db
catchsql {SELECT count(*) FROM sqlite_master}
set x {}
} {}
do_test corrupt-2.$tn.2 {
catchsql {SELECT count(*) FROM t1}
set x {}
} {}
do_test corrupt-2.$tn.3 {
catchsql {SELECT count(*) FROM t1 WHERE x>'abcdef'}
set x {}
} {}
do_test corrupt-2.$tn.4 {
catchsql {SELECT count(*) FROM t2}
set x {}
} {}
do_test corrupt-2.$tn.5 {
catchsql {CREATE TABLE t3 AS SELECT * FROM t1}
set x {}
} {}
do_test corrupt-2.$tn.6 {
catchsql {DROP TABLE t1}
set x {}
} {}
do_test corrupt-2.$tn.7 {
catchsql {PRAGMA integrity_check}
set x {}
} {}
}
#------------------------------------------------------------------------
# For these tests, swap the rootpage entries of t1 (a table) and t1i1 (an
# index on t1) in sqlite_master. Then perform a few different queries
# and make sure this is detected as corruption.
#
do_test corrupt-3.1 {
db close
copy_file test.bu test.db
sqlite3 db test.db
list
} {}
do_test corrupt-3.2 {
set t1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1i1'}]
set t1i1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1'}]
set cookie [expr [execsql {PRAGMA schema_version}] + 1]
execsql "
PRAGMA writable_schema = 1;
UPDATE sqlite_master SET rootpage = $t1_r WHERE name = 't1';
UPDATE sqlite_master SET rootpage = $t1i1_r WHERE name = 't1i1';
PRAGMA writable_schema = 0;
PRAGMA schema_version = $cookie;
"
} {}
# This one tests the case caught by code in checkin [2313].
do_test corrupt-3.3 {
db close
sqlite3 db test.db
catchsql {
INSERT INTO t1 VALUES('abc');
}
} {1 {database disk image is malformed}}
do_test corrupt-3.4 {
db close
sqlite3 db test.db
catchsql {
SELECT * FROM t1;
}
} {1 {database disk image is malformed}}
do_test corrupt-3.5 {
db close
sqlite3 db test.db
catchsql {
SELECT * FROM t1 WHERE oid = 10;
}
} {1 {database disk image is malformed}}
do_test corrupt-3.6 {
db close
sqlite3 db test.db
catchsql {
SELECT * FROM t1 WHERE x = 'abcde';
}
} {1 {database disk image is malformed}}
finish_test
+109
View File
@@ -0,0 +1,109 @@
# 2004 August 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 regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt2.test,v 1.2 2005/01/22 03:39:39 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# The following tests - corrupt2-1.* - create some databases corrupted in
# specific ways and ensure that SQLite detects them as corrupt.
#
do_test corrupt2-1.1 {
execsql {
CREATE TABLE abc(a, b, c);
}
} {}
do_test corrupt2-1.2 {
# Corrupt the 16 byte magic string at the start of the file
file delete -force corrupt.db
file delete -force corrupt.db-journal
copy_file test.db corrupt.db
set f [open corrupt.db a]
seek $f 8 start
puts $f blah
close $f
sqlite3 db2 corrupt.db
catchsql {
SELECT * FROM sqlite_master;
} db2
} {1 {file is encrypted or is not a database}}
do_test corrupt2-1.3 {
db2 close
# Corrupt the page-size (bytes 16 and 17 of page 1).
file delete -force corrupt.db
file delete -force corrupt.db-journal
copy_file test.db corrupt.db
set f [open corrupt.db a]
fconfigure $f -encoding binary
seek $f 16 start
puts -nonewline $f "\x00\xFF"
close $f
sqlite3 db2 corrupt.db
catchsql {
SELECT * FROM sqlite_master;
} db2
} {1 {file is encrypted or is not a database}}
do_test corrupt2-1.4 {
db2 close
# Corrupt the free-block list on page 1.
file delete -force corrupt.db
file delete -force corrupt.db-journal
copy_file test.db corrupt.db
set f [open corrupt.db a]
fconfigure $f -encoding binary
seek $f 101 start
puts -nonewline $f "\xFF\xFF"
close $f
sqlite3 db2 corrupt.db
catchsql {
SELECT * FROM sqlite_master;
} db2
} {1 {database disk image is malformed}}
do_test corrupt2-1.5 {
db2 close
# Corrupt the free-block list on page 1.
file delete -force corrupt.db
file delete -force corrupt.db-journal
copy_file test.db corrupt.db
set f [open corrupt.db a]
fconfigure $f -encoding binary
seek $f 101 start
puts -nonewline $f "\x00\xC8"
seek $f 200 start
puts -nonewline $f "\x00\x00"
puts -nonewline $f "\x10\x00"
close $f
sqlite3 db2 corrupt.db
catchsql {
SELECT * FROM sqlite_master;
} db2
} {1 {database disk image is malformed}}
db2 close
finish_test
+435
View File
@@ -0,0 +1,435 @@
# 2001 September 15
#
# 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 regression tests for SQLite library.
#
# The focus of this file is testing the ability of the database to
# uses its rollback journal to recover intact (no database corruption)
# from a power failure during the middle of a COMMIT. The OS interface
# modules are overloaded in a separate instance of testfixture using
# the modified I/O routines found in test6.c. These routines allow us
# to simulate the kind of file damage that occurs after a power failure.
#
# $Id: crash.test,v 1.21 2006/01/06 14:32:20 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !crashtest {
finish_test
return
}
# set repeats 100
set repeats 10
# This proc execs a seperate process that crashes midway through executing
# the SQL script $sql on database test.db.
#
# The crash occurs during a sync() of file $crashfile. When the crash
# occurs a random subset of all unsynced writes made by the process are
# written into the files on disk. Argument $crashdelay indicates the
# number of file syncs to wait before crashing.
#
# The return value is a list of two elements. The first element is a
# boolean, indicating whether or not the process actually crashed or
# reported some other error. The second element in the returned list is the
# error message. This is "child process exited abnormally" if the crash
# occured.
proc crashsql {crashdelay crashfile sql} {
set cfile [file join [pwd] $crashfile]
set f [open crash.tcl w]
puts $f "sqlite3_crashparams $crashdelay $cfile"
puts $f "set sqlite_pending_byte $::sqlite_pending_byte"
puts $f {sqlite3 db test.db}
# This block sets the cache size of the main database to 10
# pages. This is done in case the build is configured to omit
# "PRAGMA cache_size".
puts $f {db eval {SELECT * FROM sqlite_master;}}
puts $f {set bt [btree_from_db db]}
puts $f {btree_set_cache_size $bt 10}
puts $f "db eval {"
puts $f "$sql"
puts $f "}"
close $f
set r [catch {
exec [info nameofexec] crash.tcl >@stdout
} msg]
lappend r $msg
}
# The following procedure computes a "signature" for table "abc". If
# abc changes in any way, the signature should change.
proc signature {} {
return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}]
}
proc signature2 {} {
return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}]
}
#--------------------------------------------------------------------------
# Simple crash test:
#
# crash-1.1: Create a database with a table with two rows.
# crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
# the first journal-sync.
# crash-1.3: Ensure the database is in the same state as after crash-1.1.
# crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
# the first database-sync.
# crash-1.5: Ensure the database is in the same state as after crash-1.1.
# crash-1.6: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
# the second journal-sync.
# crash-1.7: Ensure the database is in the same state as after crash-1.1.
#
# Tests 1.8 through 1.11 test for crashes on the third journal sync and
# second database sync. Neither of these is required in such a small test
# case, so these tests are just to verify that the test infrastructure
# operates as expected.
#
do_test crash-1.1 {
execsql {
CREATE TABLE abc(a, b, c);
INSERT INTO abc VALUES(1, 2, 3);
INSERT INTO abc VALUES(4, 5, 6);
}
set ::sig [signature]
expr 0
} {0}
do_test crash-1.2 {
crashsql 1 test.db-journal {
DELETE FROM abc WHERE a = 1;
}
} {1 {child process exited abnormally}}
do_test crash-1.3 {
signature
} $::sig
do_test crash-1.4 {
crashsql 1 test.db {
DELETE FROM abc WHERE a = 1;
}
} {1 {child process exited abnormally}}
do_test crash-1.5 {
signature
} $::sig
do_test crash-1.6 {
crashsql 2 test.db-journal {
DELETE FROM abc WHERE a = 1;
}
} {1 {child process exited abnormally}}
do_test crash-1.7 {
catchsql {
SELECT * FROM abc;
}
} {0 {1 2 3 4 5 6}}
do_test crash-1.8 {
crashsql 3 test.db-journal {
DELETE FROM abc WHERE a = 1;
}
} {0 {}}
do_test crash-1.9 {
catchsql {
SELECT * FROM abc;
}
} {0 {4 5 6}}
do_test crash-1.10 {
crashsql 2 test.db {
DELETE FROM abc WHERE a = 4;
}
} {0 {}}
do_test crash-1.11 {
catchsql {
SELECT * FROM abc;
}
} {0 {}}
#--------------------------------------------------------------------------
# The following tests test recovery when both the database file and the the
# journal file contain corrupt data. This can happen after pages are
# written to the database file before a transaction is committed due to
# cache-pressure.
#
# crash-2.1: Insert 18 pages of data into the database.
# crash-2.2: Check the database file size looks ok.
# crash-2.3: Delete 15 or so pages (with a 10 page page-cache), then crash.
# crash-2.4: Ensure the database is in the same state as after crash-2.1.
#
# Test cases crash-2.5 and crash-2.6 check that the database is OK if the
# crash occurs during the main database file sync. But this isn't really
# different from the crash-1.* cases.
#
do_test crash-2.1 {
execsql { BEGIN }
for {set n 0} {$n < 1000} {incr n} {
execsql "INSERT INTO abc VALUES($n, [expr 2*$n], [expr 3*$n])"
}
execsql { COMMIT }
set ::sig [signature]
execsql { SELECT sum(a), sum(b), sum(c) from abc }
} {499500 999000 1498500}
do_test crash-2.2 {
expr ([file size test.db] / 1024)>16
} {1}
do_test crash-2.3 {
crashsql 2 test.db-journal {
DELETE FROM abc WHERE a < 800;
}
} {1 {child process exited abnormally}}
do_test crash-2.4 {
signature
} $sig
do_test crash-2.5 {
crashsql 1 test.db {
DELETE FROM abc WHERE a<800;
}
} {1 {child process exited abnormally}}
do_test crash-2.6 {
signature
} $sig
#--------------------------------------------------------------------------
# The crash-3.* test cases are essentially the same test as test case
# crash-2.*, but with a more complicated data set.
#
# The test is repeated a few times with different seeds for the random
# number generator in the crashing executable. Because there is no way to
# seed the random number generator directly, some SQL is added to the test
# case to 'use up' a different quantity random numbers before the test SQL
# is executed.
#
# Make sure the file is much bigger than the pager-cache (10 pages). This
# ensures that cache-spills happen regularly.
do_test crash-3.0 {
execsql {
INSERT INTO abc SELECT * FROM abc;
INSERT INTO abc SELECT * FROM abc;
INSERT INTO abc SELECT * FROM abc;
INSERT INTO abc SELECT * FROM abc;
INSERT INTO abc SELECT * FROM abc;
}
expr ([file size test.db] / 1024) > 450
} {1}
for {set i 1} {$i < $repeats} {incr i} {
set sig [signature]
do_test crash-3.$i.1 {
crashsql [expr $i%5 + 1] test.db-journal "
BEGIN;
SELECT random() FROM abc LIMIT $i;
INSERT INTO abc VALUES(randstr(10,10), 0, 0);
DELETE FROM abc WHERE random()%10!=0;
COMMIT;
"
} {1 {child process exited abnormally}}
do_test crash-3.$i.2 {
signature
} $sig
}
#--------------------------------------------------------------------------
# The following test cases - crash-4.* - test the correct recovery of the
# database when a crash occurs during a multi-file transaction.
#
# crash-4.1.*: Test recovery when crash occurs during sync() of the
# main database journal file.
# crash-4.2.*: Test recovery when crash occurs during sync() of an
# attached database journal file.
# crash-4.3.*: Test recovery when crash occurs during sync() of the master
# journal file.
#
do_test crash-4.0 {
file delete -force test2.db
file delete -force test2.db-journal
execsql {
ATTACH 'test2.db' AS aux;
PRAGMA aux.default_cache_size = 10;
CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc;
}
expr ([file size test2.db] / 1024) > 450
} {1}
for {set i 1} {$i<$repeats} {incr i} {
set sig [signature]
set sig2 [signature2]
do_test crash-4.1.$i.1 {
set c [crashsql $i test.db-journal "
ATTACH 'test2.db' AS aux;
BEGIN;
SELECT random() FROM abc LIMIT $i;
INSERT INTO abc VALUES(randstr(10,10), 0, 0);
DELETE FROM abc WHERE random()%10!=0;
INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
DELETE FROM abc2 WHERE random()%10!=0;
COMMIT;
"]
set c
} {1 {child process exited abnormally}}
do_test crash-4.1.$i.2 {
signature
} $sig
do_test crash-4.1.$i.3 {
signature2
} $sig2
}
set i 0
while {[incr i]} {
set sig [signature]
set sig2 [signature2]
set ::fin 0
do_test crash-4.2.$i.1 {
set c [crashsql $i test2.db-journal "
ATTACH 'test2.db' AS aux;
BEGIN;
SELECT random() FROM abc LIMIT $i;
INSERT INTO abc VALUES(randstr(10,10), 0, 0);
DELETE FROM abc WHERE random()%10!=0;
INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
DELETE FROM abc2 WHERE random()%10!=0;
COMMIT;
"]
if { $c == {0 {}} } {
set ::fin 1
set c {1 {child process exited abnormally}}
}
set c
} {1 {child process exited abnormally}}
if { $::fin } break
do_test crash-4.2.$i.2 {
signature
} $sig
do_test crash-4.2.$i.3 {
signature2
} $sig2
}
for {set i 1} {$i < 5} {incr i} {
set sig [signature]
set sig2 [signature2]
do_test crash-4.3.$i.1 {
crashsql 1 test.db-mj* "
ATTACH 'test2.db' AS aux;
BEGIN;
SELECT random() FROM abc LIMIT $i;
INSERT INTO abc VALUES(randstr(10,10), 0, 0);
DELETE FROM abc WHERE random()%10!=0;
INSERT INTO abc2 VALUES(randstr(10,10), 0, 0);
DELETE FROM abc2 WHERE random()%10!=0;
COMMIT;
"
} {1 {child process exited abnormally}}
do_test crash-4.3.$i.2 {
signature
} $sig
do_test crash-4.3.$i.3 {
signature2
} $sig2
}
#--------------------------------------------------------------------------
# The following test cases - crash-5.* - exposes a bug that existed in the
# sqlite3pager_movepage() API used by auto-vacuum databases.
# database when a crash occurs during a multi-file transaction. See comments
# in test crash-5.3 for details.
#
db close
file delete -force test.db
sqlite3 db test.db
do_test crash-5.1 {
execsql {
CREATE TABLE abc(a, b, c); -- Root page 3
INSERT INTO abc VALUES(randstr(1500,1500), 0, 0); -- Overflow page 4
INSERT INTO abc SELECT * FROM abc;
INSERT INTO abc SELECT * FROM abc;
INSERT INTO abc SELECT * FROM abc;
}
} {}
do_test crash-5.2 {
expr [file size test.db] / 1024
} [expr [string match [execsql {pragma auto_vacuum}] 1] ? 11 : 10]
set sig [signature]
do_test crash-5.3 {
# The SQL below is used to expose a bug that existed in
# sqlite3pager_movepage() during development of the auto-vacuum feature. It
# functions as follows:
#
# 1: Begin a transaction.
# 2: Put page 4 on the free-list (was the overflow page for the row deleted).
# 3: Write data to page 4 (it becomes the overflow page for the row inserted).
# The old page 4 data has been written to the journal file, but the
# journal file has not been sync()hronized.
# 4: Create a table, which calls sqlite3pager_movepage() to move page 4
# to the end of the database (page 12) to make room for the new root-page.
# 5: Put pressure on the pager-cache. This results in page 4 being written
# to the database file to make space in the cache to load a new page. The
# bug was that page 4 was written to the database file before the journal
# is sync()hronized.
# 6: Commit. A crash occurs during the sync of the journal file.
#
# End result: Before the bug was fixed, data has been written to page 4 of the
# database file and the journal file does not contain trustworthy rollback
# data for this page.
#
crashsql 1 test.db-journal {
BEGIN; -- 1
DELETE FROM abc WHERE oid = 1; -- 2
INSERT INTO abc VALUES(randstr(1500,1500), 0, 0); -- 3
CREATE TABLE abc2(a, b, c); -- 4
SELECT * FROM abc; -- 5
COMMIT; -- 6
}
} {1 {child process exited abnormally}}
integrity_check crash-5.4
do_test crash-5.5 {
signature
} $sig
#--------------------------------------------------------------------------
# The following test cases - crash-6.* - test that a DROP TABLE operation
# is correctly rolled back in the event of a crash while the database file
# is being written. This is mainly to test that all pages are written to the
# journal file before truncation in an auto-vacuum database.
#
do_test crash-6.1 {
crashsql 1 test.db {
DROP TABLE abc;
}
} {1 {child process exited abnormally}}
do_test crash-6.2 {
signature
} $sig
#--------------------------------------------------------------------------
# These test cases test the case where the master journal file name is
# corrupted slightly so that the corruption has to be detected by the
# checksum.
do_test crash-7.1 {
crashsql 1 test.db {
ATTACH 'test2.db' AS aux;
BEGIN;
INSERT INTO abc VALUES(randstr(1500,1500), 0, 0);
INSERT INTO abc2 VALUES(randstr(1500,1500), 0, 0);
COMMIT;
}
# Change the checksum value for the master journal name.
set f [open test.db-journal a]
fconfigure $f -encoding binary
seek $f [expr [file size test.db-journal] - 12]
puts -nonewline $f "\00\00\00\00"
close $f
} {}
do_test crash-7.2 {
signature
} $sig
finish_test
+288
View File
@@ -0,0 +1,288 @@
# 2003 October 31
#
# 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 regression tests for SQLite library. The
# focus of this file is testing date and time functions.
#
# $Id: date.test,v 1.17 2006/09/25 18:03:29 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Skip this whole file if date and time functions are omitted
# at compile-time
#
ifcapable {!datetime} {
finish_test
return
}
proc datetest {tnum expr result} {
do_test date-$tnum [subst {
execsql "SELECT coalesce($expr,'NULL')"
}] [list $result]
}
set tcl_precision 15
datetest 1.1 julianday('2000-01-01') 2451544.5
datetest 1.2 julianday('1970-01-01') 2440587.5
datetest 1.3 julianday('1910-04-20') 2418781.5
datetest 1.4 julianday('1986-02-09') 2446470.5
datetest 1.5 julianday('12:00:00') 2451545.0
datetest 1.6 {julianday('2000-01-01 12:00:00')} 2451545.0
datetest 1.7 {julianday('2000-01-01 12:00')} 2451545.0
datetest 1.8 julianday('bogus') NULL
datetest 1.9 julianday('1999-12-31') 2451543.5
datetest 1.10 julianday('1999-12-32') NULL
datetest 1.11 julianday('1999-13-01') NULL
datetest 1.12 julianday('2003-02-31') 2452701.5
datetest 1.13 julianday('2003-03-03') 2452701.5
datetest 1.14 julianday('+2000-01-01') NULL
datetest 1.15 julianday('200-01-01') NULL
datetest 1.16 julianday('2000-1-01') NULL
datetest 1.17 julianday('2000-01-1') NULL
datetest 1.18.1 {julianday('2000-01-01 12:00:00')} 2451545.0
datetest 1.18.2 {julianday('2000-01-01T12:00:00')} 2451545.0
datetest 1.18.3 {julianday('2000-01-01 T12:00:00')} 2451545.0
datetest 1.18.4 {julianday('2000-01-01T 12:00:00')} 2451545.0
datetest 1.18.4 {julianday('2000-01-01 T 12:00:00')} 2451545.0
datetest 1.19 {julianday('2000-01-01 12:00:00.1')} 2451545.00000116
datetest 1.20 {julianday('2000-01-01 12:00:00.01')} 2451545.00000012
datetest 1.21 {julianday('2000-01-01 12:00:00.001')} 2451545.00000001
datetest 1.22 {julianday('2000-01-01 12:00:00.')} NULL
datetest 1.23 julianday(12345.6) 12345.6
datetest 1.24 {julianday('2001-01-01 12:00:00 bogus')} NULL
datetest 1.25 {julianday('2001-01-01 bogus')} NULL
datetest 1.26 {julianday('2001-01-01 12:60:00')} NULL
datetest 1.27 {julianday('2001-01-01 12:59:60')} NULL
datetest 2.1 datetime(0,'unixepoch') {1970-01-01 00:00:00}
datetest 2.2 datetime(946684800,'unixepoch') {2000-01-01 00:00:00}
datetest 2.3 {date('2003-10-22','weekday 0')} 2003-10-26
datetest 2.4 {date('2003-10-22','weekday 1')} 2003-10-27
datetest 2.5 {date('2003-10-22','weekday 2')} 2003-10-28
datetest 2.6 {date('2003-10-22','weekday 3')} 2003-10-22
datetest 2.7 {date('2003-10-22','weekday 4')} 2003-10-23
datetest 2.8 {date('2003-10-22','weekday 5')} 2003-10-24
datetest 2.9 {date('2003-10-22','weekday 6')} 2003-10-25
datetest 2.10 {date('2003-10-22','weekday 7')} NULL
datetest 2.11 {date('2003-10-22','weekday 5.5')} NULL
datetest 2.12 {datetime('2003-10-22 12:34','weekday 0')} {2003-10-26 12:34:00}
datetest 2.13 {datetime('2003-10-22 12:34','start of month')} \
{2003-10-01 00:00:00}
datetest 2.14 {datetime('2003-10-22 12:34','start of year')} \
{2003-01-01 00:00:00}
datetest 2.15 {datetime('2003-10-22 12:34','start of day')} \
{2003-10-22 00:00:00}
datetest 2.16 time('12:34:56.43') 12:34:56
datetest 2.17 {datetime('2003-10-22 12:34','1 day')} {2003-10-23 12:34:00}
datetest 2.18 {datetime('2003-10-22 12:34','+1 day')} {2003-10-23 12:34:00}
datetest 2.19 {datetime('2003-10-22 12:34','+1.25 day')} {2003-10-23 18:34:00}
datetest 2.20 {datetime('2003-10-22 12:34','-1.0 day')} {2003-10-21 12:34:00}
datetest 2.21 {datetime('2003-10-22 12:34','1 month')} {2003-11-22 12:34:00}
datetest 2.22 {datetime('2003-10-22 12:34','11 month')} {2004-09-22 12:34:00}
datetest 2.23 {datetime('2003-10-22 12:34','-13 month')} {2002-09-22 12:34:00}
datetest 2.24 {datetime('2003-10-22 12:34','1.5 months')} {2003-12-07 12:34:00}
datetest 2.25 {datetime('2003-10-22 12:34','-5 years')} {1998-10-22 12:34:00}
datetest 2.26 {datetime('2003-10-22 12:34','+10.5 minutes')} \
{2003-10-22 12:44:30}
datetest 2.27 {datetime('2003-10-22 12:34','-1.25 hours')} \
{2003-10-22 11:19:00}
datetest 2.28 {datetime('2003-10-22 12:34','11.25 seconds')} \
{2003-10-22 12:34:11}
datetest 2.29 {datetime('2003-10-22 12:24','+5 bogus')} NULL
datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31
datetest 3.2 {strftime('%f','2003-10-31 12:34:56.432')} 56.432
datetest 3.3 {strftime('%H','2003-10-31 12:34:56.432')} 12
datetest 3.4 {strftime('%j','2003-10-31 12:34:56.432')} 304
datetest 3.5 {strftime('%J','2003-10-31 12:34:56.432')} 2452944.024264259
datetest 3.6 {strftime('%m','2003-10-31 12:34:56.432')} 10
datetest 3.7 {strftime('%M','2003-10-31 12:34:56.432')} 34
datetest 3.8 {strftime('%s','2003-10-31 12:34:56.432')} 1067603696
datetest 3.9 {strftime('%S','2003-10-31 12:34:56.432')} 56
datetest 3.10 {strftime('%w','2003-10-31 12:34:56.432')} 5
datetest 3.11.1 {strftime('%W','2003-10-31 12:34:56.432')} 43
datetest 3.11.2 {strftime('%W','2004-01-01')} 00
datetest 3.11.3 {strftime('%W','2004-01-02')} 00
datetest 3.11.4 {strftime('%W','2004-01-03')} 00
datetest 3.11.5 {strftime('%W','2004-01-04')} 00
datetest 3.11.6 {strftime('%W','2004-01-05')} 01
datetest 3.11.7 {strftime('%W','2004-01-06')} 01
datetest 3.11.8 {strftime('%W','2004-01-07')} 01
datetest 3.11.9 {strftime('%W','2004-01-08')} 01
datetest 3.11.10 {strftime('%W','2004-01-09')} 01
datetest 3.11.11 {strftime('%W','2004-07-18')} 28
datetest 3.11.12 {strftime('%W','2004-12-31')} 52
datetest 3.11.13 {strftime('%W','2007-12-31')} 53
datetest 3.11.14 {strftime('%W','2007-01-01')} 01
datetest 3.12 {strftime('%Y','2003-10-31 12:34:56.432')} 2003
datetest 3.13 {strftime('%%','2003-10-31 12:34:56.432')} %
datetest 3.14 {strftime('%_','2003-10-31 12:34:56.432')} NULL
datetest 3.15 {strftime('%Y-%m-%d','2003-10-31')} 2003-10-31
proc repeat {n txt} {
set x {}
while {$n>0} {
append x $txt
incr n -1
}
return $x
}
datetest 3.16 "strftime('[repeat 200 %Y]','2003-10-31')" [repeat 200 2003]
datetest 3.17 "strftime('[repeat 200 abc%m123]','2003-10-31')" \
[repeat 200 abc10123]
set sqlite_current_time 1157124367
datetest 4.1 {date('now')} {2006-09-01}
set sqlite_current_time 0
datetest 5.1 {datetime('1994-04-16 14:00:00 +05:00')} {1994-04-16 09:00:00}
datetest 5.2 {datetime('1994-04-16 14:00:00 -05:15')} {1994-04-16 19:15:00}
datetest 5.3 {datetime('1994-04-16 05:00:00 +08:30')} {1994-04-15 20:30:00}
datetest 5.4 {datetime('1994-04-16 14:00:00 -11:55')} {1994-04-17 01:55:00}
datetest 5.5 {datetime('1994-04-16 14:00:00 -11:60')} NULL
# localtime->utc and utc->localtime conversions. These tests only work
# if the localtime is in the US Eastern Time (the time in Charlotte, NC
# and in New York.)
#
set tzoffset [db one {
SELECT CAST(24*(julianday('2006-09-01') -
julianday('2006-09-01','localtime'))+0.5
AS INT)
}]
if {$tzoffset==4} {
datetest 6.1 {datetime('2000-10-29 05:59:00','localtime')}\
{2000-10-29 01:59:00}
datetest 6.2 {datetime('2000-10-29 06:00:00','localtime')}\
{2000-10-29 01:00:00}
datetest 6.3 {datetime('2000-04-02 06:59:00','localtime')}\
{2000-04-02 01:59:00}
datetest 6.4 {datetime('2000-04-02 07:00:00','localtime')}\
{2000-04-02 03:00:00}
datetest 6.5 {datetime('2000-10-29 01:59:00','utc')} {2000-10-29 05:59:00}
datetest 6.6 {datetime('2000-10-29 02:00:00','utc')} {2000-10-29 07:00:00}
datetest 6.7 {datetime('2000-04-02 01:59:00','utc')} {2000-04-02 06:59:00}
datetest 6.8 {datetime('2000-04-02 02:00:00','utc')} {2000-04-02 06:00:00}
datetest 6.10 {datetime('2000-01-01 12:00:00','localtime')} \
{2000-01-01 07:00:00}
datetest 6.11 {datetime('1969-01-01 12:00:00','localtime')} \
{1969-01-01 07:00:00}
datetest 6.12 {datetime('2039-01-01 12:00:00','localtime')} \
{2039-01-01 07:00:00}
datetest 6.13 {datetime('2000-07-01 12:00:00','localtime')} \
{2000-07-01 08:00:00}
datetest 6.14 {datetime('1969-07-01 12:00:00','localtime')} \
{1969-07-01 07:00:00}
datetest 6.15 {datetime('2039-07-01 12:00:00','localtime')} \
{2039-07-01 07:00:00}
set sqlite_current_time \
[db eval {SELECT strftime('%s','2000-07-01 12:34:56')}]
datetest 6.16 {datetime('now','localtime')} {2000-07-01 08:34:56}
set sqlite_current_time 0
}
# Date-time functions that contain NULL arguments return a NULL
# result.
#
datetest 7.1 {datetime(null)} NULL
datetest 7.2 {datetime('now',null)} NULL
datetest 7.3 {datetime('now','localtime',null)} NULL
datetest 7.4 {time(null)} NULL
datetest 7.5 {time('now',null)} NULL
datetest 7.6 {time('now','localtime',null)} NULL
datetest 7.7 {date(null)} NULL
datetest 7.8 {date('now',null)} NULL
datetest 7.9 {date('now','localtime',null)} NULL
datetest 7.10 {julianday(null)} NULL
datetest 7.11 {julianday('now',null)} NULL
datetest 7.12 {julianday('now','localtime',null)} NULL
datetest 7.13 {strftime(null,'now')} NULL
datetest 7.14 {strftime('%s',null)} NULL
datetest 7.15 {strftime('%s','now',null)} NULL
datetest 7.16 {strftime('%s','now','localtime',null)} NULL
# Test modifiers when the date begins as a julian day number - to
# make sure the HH:MM:SS is preserved. Ticket #551.
#
set sqlite_current_time [db eval {SELECT strftime('%s','2003-10-22 12:34:00')}]
datetest 8.1 {datetime('now','weekday 0')} {2003-10-26 12:34:00}
datetest 8.2 {datetime('now','weekday 1')} {2003-10-27 12:34:00}
datetest 8.3 {datetime('now','weekday 2')} {2003-10-28 12:34:00}
datetest 8.4 {datetime('now','weekday 3')} {2003-10-22 12:34:00}
datetest 8.5 {datetime('now','start of month')} {2003-10-01 00:00:00}
datetest 8.6 {datetime('now','start of year')} {2003-01-01 00:00:00}
datetest 8.7 {datetime('now','start of day')} {2003-10-22 00:00:00}
datetest 8.8 {datetime('now','1 day')} {2003-10-23 12:34:00}
datetest 8.9 {datetime('now','+1 day')} {2003-10-23 12:34:00}
datetest 8.10 {datetime('now','+1.25 day')} {2003-10-23 18:34:00}
datetest 8.11 {datetime('now','-1.0 day')} {2003-10-21 12:34:00}
datetest 8.12 {datetime('now','1 month')} {2003-11-22 12:34:00}
datetest 8.13 {datetime('now','11 month')} {2004-09-22 12:34:00}
datetest 8.14 {datetime('now','-13 month')} {2002-09-22 12:34:00}
datetest 8.15 {datetime('now','1.5 months')} {2003-12-07 12:34:00}
datetest 8.16 {datetime('now','-5 years')} {1998-10-22 12:34:00}
datetest 8.17 {datetime('now','+10.5 minutes')} {2003-10-22 12:44:30}
datetest 8.18 {datetime('now','-1.25 hours')} {2003-10-22 11:19:00}
datetest 8.19 {datetime('now','11.25 seconds')} {2003-10-22 12:34:11}
set sqlite_current_time 0
# Negative years work. Example: '-4713-11-26' is JD 1.5.
#
datetest 9.1 {julianday('-4713-11-24 12:00:00')} {0.0}
datetest 9.2 {julianday(datetime(5))} {5.0}
datetest 9.3 {julianday(datetime(10))} {10.0}
datetest 9.4 {julianday(datetime(100))} {100.0}
datetest 9.5 {julianday(datetime(1000))} {1000.0}
datetest 9.6 {julianday(datetime(10000))} {10000.0}
datetest 9.7 {julianday(datetime(100000))} {100000.0}
# datetime() with just an HH:MM:SS correctly inserts the date 2000-01-01.
#
datetest 10.1 {datetime('01:02:03')} {2000-01-01 01:02:03}
datetest 10.2 {date('01:02:03')} {2000-01-01}
datetest 10.3 {strftime('%Y-%m-%d %H:%M','01:02:03')} {2000-01-01 01:02}
# Test the new HH:MM:SS modifier
#
datetest 11.1 {datetime('2004-02-28 20:00:00', '-01:20:30')} \
{2004-02-28 18:39:30}
datetest 11.2 {datetime('2004-02-28 20:00:00', '+12:30:00')} \
{2004-02-29 08:30:00}
datetest 11.3 {datetime('2004-02-28 20:00:00', '+12:30')} \
{2004-02-29 08:30:00}
datetest 11.4 {datetime('2004-02-28 20:00:00', '12:30')} \
{2004-02-29 08:30:00}
datetest 11.5 {datetime('2004-02-28 20:00:00', '-12:00')} \
{2004-02-28 08:00:00}
datetest 11.6 {datetime('2004-02-28 20:00:00', '-12:01')} \
{2004-02-28 07:59:00}
datetest 11.7 {datetime('2004-02-28 20:00:00', '-11:59')} \
{2004-02-28 08:01:00}
datetest 11.8 {datetime('2004-02-28 20:00:00', '11:59')} \
{2004-02-29 07:59:00}
datetest 11.9 {datetime('2004-02-28 20:00:00', '12:01')} \
{2004-02-29 08:01:00}
datetest 11.10 {datetime('2004-02-28 20:00:00', '12:60')} NULL
# Ticket #1964
datetest 12.1 {datetime('2005-09-01')} {2005-09-01 00:00:00}
datetest 12.2 {datetime('2005-09-01','+0 hours')} {2005-09-01 00:00:00}
# Ticket #1991
do_test date-13.1 {
execsql {
SELECT strftime('%Y-%m-%d %H:%M:%f', julianday('2006-09-24T10:50:26.047'))
}
} {{2006-09-24 10:50:26.047}}
finish_test
+52
View File
@@ -0,0 +1,52 @@
# 2005 August 18
#
# 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 regression tests for SQLite library. The
# focus of this file is testing corner cases of the DEFAULT syntax
# on table definitions.
#
# $Id: default.test,v 1.2 2005/08/20 03:03:04 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable bloblit {
do_test default-1.1 {
execsql {
CREATE TABLE t1(
a INTEGER,
b BLOB DEFAULT x'6869'
);
INSERT INTO t1(a) VALUES(1);
SELECT * from t1;
}
} {1 hi}
}
do_test default-1.2 {
execsql {
CREATE TABLE t2(
x INTEGER,
y INTEGER DEFAULT NULL
);
INSERT INTO t2(x) VALUES(1);
SELECT * FROM t2;
}
} {1 {}}
do_test default-1.3 {
catchsql {
CREATE TABLE t3(
x INTEGER,
y INTEGER DEFAULT (max(x,5))
)
}
} {1 {default value of column [y] is not constant}}
finish_test
+313
View File
@@ -0,0 +1,313 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the DELETE FROM statement.
#
# $Id: delete.test,v 1.21 2006/01/03 00:33:50 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Try to delete from a non-existant table.
#
do_test delete-1.1 {
set v [catch {execsql {DELETE FROM test1}} msg]
lappend v $msg
} {1 {no such table: test1}}
# Try to delete from sqlite_master
#
do_test delete-2.1 {
set v [catch {execsql {DELETE FROM sqlite_master}} msg]
lappend v $msg
} {1 {table sqlite_master may not be modified}}
# Delete selected entries from a table with and without an index.
#
do_test delete-3.1.1 {
execsql {CREATE TABLE table1(f1 int, f2 int)}
execsql {INSERT INTO table1 VALUES(1,2)}
execsql {INSERT INTO table1 VALUES(2,4)}
execsql {INSERT INTO table1 VALUES(3,8)}
execsql {INSERT INTO table1 VALUES(4,16)}
execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 3 8 4 16}
do_test delete-3.1.2 {
execsql {DELETE FROM table1 WHERE f1=3}
} {}
do_test delete-3.1.3 {
execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 4 16}
do_test delete-3.1.4 {
execsql {CREATE INDEX index1 ON table1(f1)}
execsql {PRAGMA count_changes=on}
ifcapable explain {
execsql {EXPLAIN DELETE FROM table1 WHERE f1=3}
}
execsql {DELETE FROM 'table1' WHERE f1=3}
} {0}
do_test delete-3.1.5 {
execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 2 4 4 16}
do_test delete-3.1.6.1 {
execsql {DELETE FROM table1 WHERE f1=2}
} {1}
do_test delete-3.1.6.2 {
db changes
} 1
do_test delete-3.1.7 {
execsql {SELECT * FROM table1 ORDER BY f1}
} {1 2 4 16}
integrity_check delete-3.2
# Semantic errors in the WHERE clause
#
do_test delete-4.1 {
execsql {CREATE TABLE table2(f1 int, f2 int)}
set v [catch {execsql {DELETE FROM table2 WHERE f3=5}} msg]
lappend v $msg
} {1 {no such column: f3}}
do_test delete-4.2 {
set v [catch {execsql {DELETE FROM table2 WHERE xyzzy(f1+4)}} msg]
lappend v $msg
} {1 {no such function: xyzzy}}
integrity_check delete-4.3
# Lots of deletes
#
do_test delete-5.1.1 {
execsql {DELETE FROM table1}
} {2}
do_test delete-5.1.2 {
execsql {SELECT count(*) FROM table1}
} {0}
do_test delete-5.2.1 {
execsql {BEGIN TRANSACTION}
for {set i 1} {$i<=200} {incr i} {
execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
}
execsql {COMMIT}
execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.2.2 {
execsql {DELETE FROM table1}
} {200}
do_test delete-5.2.3 {
execsql {BEGIN TRANSACTION}
for {set i 1} {$i<=200} {incr i} {
execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
}
execsql {COMMIT}
execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.2.4 {
execsql {PRAGMA count_changes=off}
execsql {DELETE FROM table1}
} {}
do_test delete-5.2.5 {
execsql {SELECT count(*) FROM table1}
} {0}
do_test delete-5.2.6 {
execsql {BEGIN TRANSACTION}
for {set i 1} {$i<=200} {incr i} {
execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
}
execsql {COMMIT}
execsql {SELECT count(*) FROM table1}
} {200}
do_test delete-5.3 {
for {set i 1} {$i<=200} {incr i 4} {
execsql "DELETE FROM table1 WHERE f1==$i"
}
execsql {SELECT count(*) FROM table1}
} {150}
do_test delete-5.4.1 {
execsql "DELETE FROM table1 WHERE f1>50"
db changes
} [db one {SELECT count(*) FROM table1 WHERE f1>50}]
do_test delete-5.4.2 {
execsql {SELECT count(*) FROM table1}
} {37}
do_test delete-5.5 {
for {set i 1} {$i<=70} {incr i 3} {
execsql "DELETE FROM table1 WHERE f1==$i"
}
execsql {SELECT f1 FROM table1 ORDER BY f1}
} {2 3 6 8 11 12 14 15 18 20 23 24 26 27 30 32 35 36 38 39 42 44 47 48 50}
do_test delete-5.6 {
for {set i 1} {$i<40} {incr i} {
execsql "DELETE FROM table1 WHERE f1==$i"
}
execsql {SELECT f1 FROM table1 ORDER BY f1}
} {42 44 47 48 50}
do_test delete-5.7 {
execsql "DELETE FROM table1 WHERE f1!=48"
execsql {SELECT f1 FROM table1 ORDER BY f1}
} {48}
integrity_check delete-5.8
# Delete large quantities of data. We want to test the List overflow
# mechanism in the vdbe.
#
do_test delete-6.1 {
execsql {BEGIN; DELETE FROM table1}
for {set i 1} {$i<=3000} {incr i} {
execsql "INSERT INTO table1 VALUES($i,[expr {$i*$i}])"
}
execsql {DELETE FROM table2}
for {set i 1} {$i<=3000} {incr i} {
execsql "INSERT INTO table2 VALUES($i,[expr {$i*$i}])"
}
execsql {COMMIT}
execsql {SELECT count(*) FROM table1}
} {3000}
do_test delete-6.2 {
execsql {SELECT count(*) FROM table2}
} {3000}
do_test delete-6.3 {
execsql {SELECT f1 FROM table1 WHERE f1<10 ORDER BY f1}
} {1 2 3 4 5 6 7 8 9}
do_test delete-6.4 {
execsql {SELECT f1 FROM table2 WHERE f1<10 ORDER BY f1}
} {1 2 3 4 5 6 7 8 9}
do_test delete-6.5.1 {
execsql {DELETE FROM table1 WHERE f1>7}
db changes
} {2993}
do_test delete-6.5.2 {
execsql {SELECT f1 FROM table1 ORDER BY f1}
} {1 2 3 4 5 6 7}
do_test delete-6.6 {
execsql {DELETE FROM table2 WHERE f1>7}
execsql {SELECT f1 FROM table2 ORDER BY f1}
} {1 2 3 4 5 6 7}
do_test delete-6.7 {
execsql {DELETE FROM table1}
execsql {SELECT f1 FROM table1}
} {}
do_test delete-6.8 {
execsql {INSERT INTO table1 VALUES(2,3)}
execsql {SELECT f1 FROM table1}
} {2}
do_test delete-6.9 {
execsql {DELETE FROM table2}
execsql {SELECT f1 FROM table2}
} {}
do_test delete-6.10 {
execsql {INSERT INTO table2 VALUES(2,3)}
execsql {SELECT f1 FROM table2}
} {2}
integrity_check delete-6.11
do_test delete-7.1 {
execsql {
CREATE TABLE t3(a);
INSERT INTO t3 VALUES(1);
INSERT INTO t3 SELECT a+1 FROM t3;
INSERT INTO t3 SELECT a+2 FROM t3;
SELECT * FROM t3;
}
} {1 2 3 4}
ifcapable {trigger} {
do_test delete-7.2 {
execsql {
CREATE TABLE cnt(del);
INSERT INTO cnt VALUES(0);
CREATE TRIGGER r1 AFTER DELETE ON t3 FOR EACH ROW BEGIN
UPDATE cnt SET del=del+1;
END;
DELETE FROM t3 WHERE a<2;
SELECT * FROM t3;
}
} {2 3 4}
do_test delete-7.3 {
execsql {
SELECT * FROM cnt;
}
} {1}
do_test delete-7.4 {
execsql {
DELETE FROM t3;
SELECT * FROM t3;
}
} {}
do_test delete-7.5 {
execsql {
SELECT * FROM cnt;
}
} {4}
do_test delete-7.6 {
execsql {
INSERT INTO t3 VALUES(1);
INSERT INTO t3 SELECT a+1 FROM t3;
INSERT INTO t3 SELECT a+2 FROM t3;
CREATE TABLE t4 AS SELECT * FROM t3;
PRAGMA count_changes=ON;
DELETE FROM t3;
DELETE FROM t4;
}
} {4 4}
} ;# endif trigger
ifcapable {!trigger} {
execsql {DELETE FROM t3}
}
integrity_check delete-7.7
# Make sure error messages are consistent when attempting to delete
# from a read-only database. Ticket #304.
#
do_test delete-8.0 {
execsql {
PRAGMA count_changes=OFF;
INSERT INTO t3 VALUES(123);
SELECT * FROM t3;
}
} {123}
db close
catch {file attributes test.db -permissions 0444}
catch {file attributes test.db -readonly 1}
sqlite3 db test.db
set ::DB [sqlite3_connection_pointer db]
do_test delete-8.1 {
catchsql {
DELETE FROM t3;
}
} {1 {attempt to write a readonly database}}
do_test delete-8.2 {
execsql {SELECT * FROM t3}
} {123}
do_test delete-8.3 {
catchsql {
DELETE FROM t3 WHERE 1;
}
} {1 {attempt to write a readonly database}}
do_test delete-8.4 {
execsql {SELECT * FROM t3}
} {123}
# Update for v3: In v2 the DELETE statement would succeed because no
# database writes actually occur. Version 3 refuses to open a transaction
# on a read-only file, so the statement fails.
do_test delete-8.5 {
catchsql {
DELETE FROM t3 WHERE a<100;
}
# v2 result: {0 {}}
} {1 {attempt to write a readonly database}}
do_test delete-8.6 {
execsql {SELECT * FROM t3}
} {123}
integrity_check delete-8.7
finish_test
+99
View File
@@ -0,0 +1,99 @@
# 2003 September 6
#
# 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 regression tests for SQLite library. The
# focus of this script is a test to replicate the bug reported by
# ticket #842.
#
# Ticket #842 was a database corruption problem caused by a DELETE that
# removed an index entry by not the main table entry. To recreate the
# problem do this:
#
# (1) Create a table with an index. Insert some data into that table.
# (2) Start a query on the table but do not complete the query.
# (3) Try to delete a single entry from the table.
#
# Step 3 will fail because there is still a read cursor on the table.
# But the database is corrupted by the DELETE. It turns out that the
# index entry was deleted first, before the table entry. And the index
# delete worked. Thus an entry was deleted from the index but not from
# the table.
#
# The solution to the problem was to detect that the table is locked
# before the index entry is deleted.
#
# $Id: delete2.test,v 1.7 2006/08/16 16:42:48 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table that has an index.
#
do_test delete2-1.1 {
set DB [sqlite3_connection_pointer db]
execsql {
CREATE TABLE q(s string, id string, constraint pk_q primary key(id));
BEGIN;
INSERT INTO q(s,id) VALUES('hello','id.1');
INSERT INTO q(s,id) VALUES('goodbye','id.2');
INSERT INTO q(s,id) VALUES('again','id.3');
END;
SELECT * FROM q;
}
} {hello id.1 goodbye id.2 again id.3}
do_test delete2-1.2 {
execsql {
SELECT * FROM q WHERE id='id.1';
}
} {hello id.1}
integrity_check delete2-1.3
# Start a query on the table. The query should not use the index.
# Do not complete the query, thus leaving the table locked.
#
do_test delete2-1.4 {
set STMT [sqlite3_prepare $DB {SELECT * FROM q} -1 TAIL]
sqlite3_step $STMT
} SQLITE_ROW
integrity_check delete2-1.5
# Try to delete a row from the table while a read is in process.
# As of 2006-08-16, this is allowed. (It used to fail with SQLITE_LOCKED.)
#
do_test delete2-1.6 {
catchsql {
DELETE FROM q WHERE rowid=1
}
} {0 {}}
integrity_check delete2-1.7
do_test delete2-1.8 {
execsql {
SELECT * FROM q;
}
} {goodbye id.2 again id.3}
# Finalize the query, thus clearing the lock on the table. Then
# retry the delete. The delete should work this time.
#
do_test delete2-1.9 {
sqlite3_finalize $STMT
catchsql {
DELETE FROM q WHERE rowid=1
}
} {0 {}}
integrity_check delete2-1.10
do_test delete2-1.11 {
execsql {
SELECT * FROM q;
}
} {goodbye id.2 again id.3}
finish_test
+57
View File
@@ -0,0 +1,57 @@
# 2005 August 24
#
# 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 regression tests for SQLite library. The
# focus of this script is a test of the DELETE command where a
# large number of rows are deleted.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table that contains a large number of rows.
#
do_test delete3-1.1 {
execsql {
CREATE TABLE t1(x integer primary key);
BEGIN;
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 SELECT x+2 FROM t1;
INSERT INTO t1 SELECT x+4 FROM t1;
INSERT INTO t1 SELECT x+8 FROM t1;
INSERT INTO t1 SELECT x+16 FROM t1;
INSERT INTO t1 SELECT x+32 FROM t1;
INSERT INTO t1 SELECT x+64 FROM t1;
INSERT INTO t1 SELECT x+128 FROM t1;
INSERT INTO t1 SELECT x+256 FROM t1;
INSERT INTO t1 SELECT x+512 FROM t1;
INSERT INTO t1 SELECT x+1024 FROM t1;
INSERT INTO t1 SELECT x+2048 FROM t1;
INSERT INTO t1 SELECT x+4096 FROM t1;
INSERT INTO t1 SELECT x+8192 FROM t1;
INSERT INTO t1 SELECT x+16384 FROM t1;
INSERT INTO t1 SELECT x+32768 FROM t1;
INSERT INTO t1 SELECT x+65536 FROM t1;
INSERT INTO t1 SELECT x+131072 FROM t1;
INSERT INTO t1 SELECT x+262144 FROM t1;
COMMIT;
SELECT count(*) FROM t1;
}
} {524288}
do_test delete3-1.2 {
execsql {
DELETE FROM t1 WHERE x%2==0;
SELECT count(*) FROM t1;
}
} {262144}
integrity_check delete3-1.3
finish_test
+337
View File
@@ -0,0 +1,337 @@
# 2005 December 21
#
# 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 regression tests for SQLite library. The
# focus of this script is descending indices.
#
# $Id: descidx1.test,v 1.7 2006/07/11 14:17:52 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db eval {PRAGMA legacy_file_format=OFF}
# This procedure sets the value of the file-format in file 'test.db'
# to $newval. Also, the schema cookie is incremented.
#
proc set_file_format {newval} {
set bt [btree_open test.db 10 0]
btree_begin_transaction $bt
set meta [btree_get_meta $bt]
lset meta 2 $newval ;# File format
lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie
eval "btree_update_meta $bt $meta"
btree_commit $bt
btree_close $bt
}
# This procedure returns the value of the file-format in file 'test.db'.
#
proc get_file_format {{fname test.db}} {
set bt [btree_open $fname 10 0]
set meta [btree_get_meta $bt]
btree_close $bt
lindex $meta 2
}
# Verify that the file format starts as 4.
#
do_test descidx1-1.1 {
execsql {
CREATE TABLE t1(a,b);
CREATE INDEX i1 ON t1(b ASC);
}
get_file_format
} {4}
do_test descidx1-1.2 {
execsql {
CREATE INDEX i2 ON t1(a DESC);
}
get_file_format
} {4}
# Put some information in the table and verify that the descending
# index actually works.
#
do_test descidx1-2.1 {
execsql {
INSERT INTO t1 VALUES(1,1);
INSERT INTO t1 VALUES(2,2);
INSERT INTO t1 SELECT a+2, a+2 FROM t1;
INSERT INTO t1 SELECT a+4, a+4 FROM t1;
SELECT b FROM t1 WHERE a>3 AND a<7;
}
} {6 5 4}
do_test descidx1-2.2 {
execsql {
SELECT a FROM t1 WHERE b>3 AND b<7;
}
} {4 5 6}
do_test descidx1-2.3 {
execsql {
SELECT b FROM t1 WHERE a>=3 AND a<7;
}
} {6 5 4 3}
do_test descidx1-2.4 {
execsql {
SELECT b FROM t1 WHERE a>3 AND a<=7;
}
} {7 6 5 4}
do_test descidx1-2.5 {
execsql {
SELECT b FROM t1 WHERE a>=3 AND a<=7;
}
} {7 6 5 4 3}
do_test descidx1-2.6 {
execsql {
SELECT a FROM t1 WHERE b>=3 AND b<=7;
}
} {3 4 5 6 7}
# This procedure executes the SQL. Then it checks to see if the OP_Sort
# opcode was executed. If an OP_Sort did occur, then "sort" is appended
# to the result. If no OP_Sort happened, then "nosort" is appended.
#
# This procedure is used to check to make sure sorting is or is not
# occurring as expected.
#
proc cksort {sql} {
set ::sqlite_sort_count 0
set data [execsql $sql]
if {$::sqlite_sort_count} {set x sort} {set x nosort}
lappend data $x
return $data
}
# Test sorting using a descending index.
#
do_test descidx1-3.1 {
cksort {SELECT a FROM t1 ORDER BY a}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.2 {
cksort {SELECT a FROM t1 ORDER BY a ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.3 {
cksort {SELECT a FROM t1 ORDER BY a DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx1-3.4 {
cksort {SELECT b FROM t1 ORDER BY a}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.5 {
cksort {SELECT b FROM t1 ORDER BY a ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.6 {
cksort {SELECT b FROM t1 ORDER BY a DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx1-3.7 {
cksort {SELECT a FROM t1 ORDER BY b}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.8 {
cksort {SELECT a FROM t1 ORDER BY b ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.9 {
cksort {SELECT a FROM t1 ORDER BY b DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx1-3.10 {
cksort {SELECT b FROM t1 ORDER BY b}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.11 {
cksort {SELECT b FROM t1 ORDER BY b ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx1-3.12 {
cksort {SELECT b FROM t1 ORDER BY b DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx1-3.21 {
cksort {SELECT a FROM t1 WHERE a>3 AND a<8 ORDER BY a}
} {4 5 6 7 nosort}
do_test descidx1-3.22 {
cksort {SELECT a FROM t1 WHERE a>3 AND a<8 ORDER BY a ASC}
} {4 5 6 7 nosort}
do_test descidx1-3.23 {
cksort {SELECT a FROM t1 WHERE a>3 AND a<8 ORDER BY a DESC}
} {7 6 5 4 nosort}
do_test descidx1-3.24 {
cksort {SELECT b FROM t1 WHERE a>3 AND a<8 ORDER BY a}
} {4 5 6 7 nosort}
do_test descidx1-3.25 {
cksort {SELECT b FROM t1 WHERE a>3 AND a<8 ORDER BY a ASC}
} {4 5 6 7 nosort}
do_test descidx1-3.26 {
cksort {SELECT b FROM t1 WHERE a>3 AND a<8 ORDER BY a DESC}
} {7 6 5 4 nosort}
# Create a table with indices that are descending on some terms and
# ascending on others.
#
ifcapable bloblit {
do_test descidx1-4.1 {
execsql {
CREATE TABLE t2(a INT, b TEXT, c BLOB, d REAL);
CREATE INDEX i3 ON t2(a ASC, b DESC, c ASC);
CREATE INDEX i4 ON t2(b DESC, a ASC, d DESC);
INSERT INTO t2 VALUES(1,'one',x'31',1.0);
INSERT INTO t2 VALUES(2,'two',x'3232',2.0);
INSERT INTO t2 VALUES(3,'three',x'333333',3.0);
INSERT INTO t2 VALUES(4,'four',x'34343434',4.0);
INSERT INTO t2 VALUES(5,'five',x'3535353535',5.0);
INSERT INTO t2 VALUES(6,'six',x'363636363636',6.0);
INSERT INTO t2 VALUES(2,'two',x'323232',2.1);
INSERT INTO t2 VALUES(2,'zwei',x'3232',2.2);
INSERT INTO t2 VALUES(2,NULL,NULL,2.3);
SELECT count(*) FROM t2;
}
} {9}
do_test descidx1-4.2 {
execsql {
SELECT d FROM t2 ORDER BY a;
}
} {1.0 2.2 2.0 2.1 2.3 3.0 4.0 5.0 6.0}
do_test descidx1-4.3 {
execsql {
SELECT d FROM t2 WHERE a>=2;
}
} {2.2 2.0 2.1 2.3 3.0 4.0 5.0 6.0}
do_test descidx1-4.4 {
execsql {
SELECT d FROM t2 WHERE a>2;
}
} {3.0 4.0 5.0 6.0}
do_test descidx1-4.5 {
execsql {
SELECT d FROM t2 WHERE a=2 AND b>'two';
}
} {2.2}
do_test descidx1-4.6 {
execsql {
SELECT d FROM t2 WHERE a=2 AND b>='two';
}
} {2.2 2.0 2.1}
do_test descidx1-4.7 {
execsql {
SELECT d FROM t2 WHERE a=2 AND b<'two';
}
} {}
do_test descidx1-4.8 {
execsql {
SELECT d FROM t2 WHERE a=2 AND b<='two';
}
} {2.0 2.1}
}
do_test descidx1-5.1 {
execsql {
CREATE TABLE t3(a,b,c,d);
CREATE INDEX t3i1 ON t3(a DESC, b ASC, c DESC, d ASC);
INSERT INTO t3 VALUES(0,0,0,0);
INSERT INTO t3 VALUES(0,0,0,1);
INSERT INTO t3 VALUES(0,0,1,0);
INSERT INTO t3 VALUES(0,0,1,1);
INSERT INTO t3 VALUES(0,1,0,0);
INSERT INTO t3 VALUES(0,1,0,1);
INSERT INTO t3 VALUES(0,1,1,0);
INSERT INTO t3 VALUES(0,1,1,1);
INSERT INTO t3 VALUES(1,0,0,0);
INSERT INTO t3 VALUES(1,0,0,1);
INSERT INTO t3 VALUES(1,0,1,0);
INSERT INTO t3 VALUES(1,0,1,1);
INSERT INTO t3 VALUES(1,1,0,0);
INSERT INTO t3 VALUES(1,1,0,1);
INSERT INTO t3 VALUES(1,1,1,0);
INSERT INTO t3 VALUES(1,1,1,1);
SELECT count(*) FROM t3;
}
} {16}
do_test descidx1-5.2 {
cksort {
SELECT a||b||c||d FROM t3 ORDER BY a,b,c,d;
}
} {0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 sort}
do_test descidx1-5.3 {
cksort {
SELECT a||b||c||d FROM t3 ORDER BY a DESC, b ASC, c DESC, d ASC;
}
} {1010 1011 1000 1001 1110 1111 1100 1101 0010 0011 0000 0001 0110 0111 0100 0101 nosort}
do_test descidx1-5.4 {
cksort {
SELECT a||b||c||d FROM t3 ORDER BY a ASC, b DESC, c ASC, d DESC;
}
} {0101 0100 0111 0110 0001 0000 0011 0010 1101 1100 1111 1110 1001 1000 1011 1010 nosort}
do_test descidx1-5.5 {
cksort {
SELECT a||b||c FROM t3 WHERE d=0 ORDER BY a DESC, b ASC, c DESC
}
} {101 100 111 110 001 000 011 010 nosort}
do_test descidx1-5.6 {
cksort {
SELECT a||b||c FROM t3 WHERE d=0 ORDER BY a ASC, b DESC, c ASC
}
} {010 011 000 001 110 111 100 101 nosort}
do_test descidx1-5.7 {
cksort {
SELECT a||b||c FROM t3 WHERE d=0 ORDER BY a ASC, b DESC, c DESC
}
} {011 010 001 000 111 110 101 100 sort}
do_test descidx1-5.8 {
cksort {
SELECT a||b||c FROM t3 WHERE d=0 ORDER BY a ASC, b ASC, c ASC
}
} {000 001 010 011 100 101 110 111 sort}
do_test descidx1-5.9 {
cksort {
SELECT a||b||c FROM t3 WHERE d=0 ORDER BY a DESC, b DESC, c ASC
}
} {110 111 100 101 010 011 000 001 sort}
# Test the legacy_file_format pragma here because we have access to
# the get_file_format command.
#
ifcapable legacyformat {
do_test descidx1-6.1 {
db close
file delete -force test.db test.db-journal
sqlite3 db test.db
execsql {PRAGMA legacy_file_format}
} {1}
} else {
do_test descidx1-6.1 {
db close
file delete -force test.db test.db-journal
sqlite3 db test.db
execsql {PRAGMA legacy_file_format}
} {0}
}
do_test descidx1-6.2 {
execsql {PRAGMA legacy_file_format=YES}
execsql {PRAGMA legacy_file_format}
} {1}
do_test descidx1-6.3 {
execsql {
CREATE TABLE t1(a,b,c);
}
get_file_format
} {1}
do_test descidx1-6.4 {
db close
file delete -force test.db test.db-journal
sqlite3 db test.db
execsql {PRAGMA legacy_file_format=NO}
execsql {PRAGMA legacy_file_format}
} {0}
do_test descidx1-6.5 {
execsql {
CREATE TABLE t1(a,b,c);
}
get_file_format
} {4}
finish_test
+184
View File
@@ -0,0 +1,184 @@
# 2005 December 21
#
# 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 regression tests for SQLite library. The
# focus of this script is descending indices.
#
# $Id: descidx2.test,v 1.4 2006/07/11 14:17:52 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db eval {PRAGMA legacy_file_format=OFF}
# This procedure sets the value of the file-format in file 'test.db'
# to $newval. Also, the schema cookie is incremented.
#
proc set_file_format {newval} {
set bt [btree_open test.db 10 0]
btree_begin_transaction $bt
set meta [btree_get_meta $bt]
lset meta 2 $newval ;# File format
lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie
eval "btree_update_meta $bt $meta"
btree_commit $bt
btree_close $bt
}
# This procedure returns the value of the file-format in file 'test.db'.
#
proc get_file_format {{fname test.db}} {
set bt [btree_open $fname 10 0]
set meta [btree_get_meta $bt]
btree_close $bt
lindex $meta 2
}
# Verify that the file format starts as 4
#
do_test descidx2-1.1 {
execsql {
CREATE TABLE t1(a,b);
CREATE INDEX i1 ON t1(b ASC);
}
get_file_format
} {4}
do_test descidx2-1.2 {
execsql {
CREATE INDEX i2 ON t1(a DESC);
}
get_file_format
} {4}
# Before adding any information to the database, set the file format
# back to three. Then close and reopen the database. With the file
# format set to three, SQLite should ignore the DESC argument on the
# index.
#
do_test descidx2-2.0 {
set_file_format 3
db close
sqlite3 db test.db
get_file_format
} {3}
# Put some information in the table and verify that the DESC
# on the index is ignored.
#
do_test descidx2-2.1 {
execsql {
INSERT INTO t1 VALUES(1,1);
INSERT INTO t1 VALUES(2,2);
INSERT INTO t1 SELECT a+2, a+2 FROM t1;
INSERT INTO t1 SELECT a+4, a+4 FROM t1;
SELECT b FROM t1 WHERE a>3 AND a<7;
}
} {4 5 6}
do_test descidx2-2.2 {
execsql {
SELECT a FROM t1 WHERE b>3 AND b<7;
}
} {4 5 6}
do_test descidx2-2.3 {
execsql {
SELECT b FROM t1 WHERE a>=3 AND a<7;
}
} {3 4 5 6}
do_test descidx2-2.4 {
execsql {
SELECT b FROM t1 WHERE a>3 AND a<=7;
}
} {4 5 6 7}
do_test descidx2-2.5 {
execsql {
SELECT b FROM t1 WHERE a>=3 AND a<=7;
}
} {3 4 5 6 7}
do_test descidx2-2.6 {
execsql {
SELECT a FROM t1 WHERE b>=3 AND b<=7;
}
} {3 4 5 6 7}
# This procedure executes the SQL. Then it checks to see if the OP_Sort
# opcode was executed. If an OP_Sort did occur, then "sort" is appended
# to the result. If no OP_Sort happened, then "nosort" is appended.
#
# This procedure is used to check to make sure sorting is or is not
# occurring as expected.
#
proc cksort {sql} {
set ::sqlite_sort_count 0
set data [execsql $sql]
if {$::sqlite_sort_count} {set x sort} {set x nosort}
lappend data $x
return $data
}
# Test sorting using a descending index.
#
do_test descidx2-3.1 {
cksort {SELECT a FROM t1 ORDER BY a}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.2 {
cksort {SELECT a FROM t1 ORDER BY a ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.3 {
cksort {SELECT a FROM t1 ORDER BY a DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx2-3.4 {
cksort {SELECT b FROM t1 ORDER BY a}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.5 {
cksort {SELECT b FROM t1 ORDER BY a ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.6 {
cksort {SELECT b FROM t1 ORDER BY a DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx2-3.7 {
cksort {SELECT a FROM t1 ORDER BY b}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.8 {
cksort {SELECT a FROM t1 ORDER BY b ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.9 {
cksort {SELECT a FROM t1 ORDER BY b DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx2-3.10 {
cksort {SELECT b FROM t1 ORDER BY b}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.11 {
cksort {SELECT b FROM t1 ORDER BY b ASC}
} {1 2 3 4 5 6 7 8 nosort}
do_test descidx2-3.12 {
cksort {SELECT b FROM t1 ORDER BY b DESC}
} {8 7 6 5 4 3 2 1 nosort}
do_test descidx2-3.21 {
cksort {SELECT a FROM t1 WHERE a>3 AND a<8 ORDER BY a}
} {4 5 6 7 nosort}
do_test descidx2-3.22 {
cksort {SELECT a FROM t1 WHERE a>3 AND a<8 ORDER BY a ASC}
} {4 5 6 7 nosort}
do_test descidx2-3.23 {
cksort {SELECT a FROM t1 WHERE a>3 AND a<8 ORDER BY a DESC}
} {7 6 5 4 nosort}
do_test descidx2-3.24 {
cksort {SELECT b FROM t1 WHERE a>3 AND a<8 ORDER BY a}
} {4 5 6 7 nosort}
do_test descidx2-3.25 {
cksort {SELECT b FROM t1 WHERE a>3 AND a<8 ORDER BY a ASC}
} {4 5 6 7 nosort}
do_test descidx2-3.26 {
cksort {SELECT b FROM t1 WHERE a>3 AND a<8 ORDER BY a DESC}
} {7 6 5 4 nosort}
finish_test
+155
View File
@@ -0,0 +1,155 @@
# 2006 January 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.
#
#*************************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is descending indices.
#
# $Id: descidx3.test,v 1.5 2006/07/11 14:17:52 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !bloblit {
finish_test
return
}
db eval {PRAGMA legacy_file_format=OFF}
# This procedure sets the value of the file-format in file 'test.db'
# to $newval. Also, the schema cookie is incremented.
#
proc set_file_format {newval} {
set bt [btree_open test.db 10 0]
btree_begin_transaction $bt
set meta [btree_get_meta $bt]
lset meta 2 $newval ;# File format
lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie
eval "btree_update_meta $bt $meta"
btree_commit $bt
btree_close $bt
}
# This procedure returns the value of the file-format in file 'test.db'.
#
proc get_file_format {{fname test.db}} {
set bt [btree_open $fname 10 0]
set meta [btree_get_meta $bt]
btree_close $bt
lindex $meta 2
}
# Verify that the file format starts as 4.
#
do_test descidx3-1.1 {
execsql {
CREATE TABLE t1(i INTEGER PRIMARY KEY,a,b,c,d);
CREATE INDEX t1i1 ON t1(a DESC, b ASC, c DESC);
CREATE INDEX t1i2 ON t1(b DESC, c ASC, d DESC);
}
get_file_format
} {4}
# Put some information in the table and verify that the descending
# index actually works.
#
do_test descidx3-2.1 {
execsql {
INSERT INTO t1 VALUES(1, NULL, NULL, NULL, NULL);
INSERT INTO t1 VALUES(2, 2, 2, 2, 2);
INSERT INTO t1 VALUES(3, 3, 3, 3, 3);
INSERT INTO t1 VALUES(4, 2.5, 2.5, 2.5, 2.5);
INSERT INTO t1 VALUES(5, -5, -5, -5, -5);
INSERT INTO t1 VALUES(6, 'six', 'six', 'six', 'six');
INSERT INTO t1 VALUES(7, x'77', x'77', x'77', x'77');
INSERT INTO t1 VALUES(8, 'eight', 'eight', 'eight', 'eight');
INSERT INTO t1 VALUES(9, x'7979', x'7979', x'7979', x'7979');
SELECT count(*) FROM t1;
}
} 9
do_test descidx3-2.2 {
execsql {
SELECT i FROM t1 ORDER BY a;
}
} {1 5 2 4 3 8 6 7 9}
do_test descidx3-2.3 {
execsql {
SELECT i FROM t1 ORDER BY a DESC;
}
} {9 7 6 8 3 4 2 5 1}
# The "natural" order for the index is decreasing
do_test descidx3-2.4 {
execsql {
SELECT i FROM t1 WHERE a<=x'7979';
}
} {9 7 6 8 3 4 2 5}
do_test descidx3-2.5 {
execsql {
SELECT i FROM t1 WHERE a>-99;
}
} {9 7 6 8 3 4 2 5}
# Even when all values of t1.a are the same, sorting by A returns
# the rows in reverse order because this the natural order of the
# index.
#
do_test descidx3-3.1 {
execsql {
UPDATE t1 SET a=1;
SELECT i FROM t1 ORDER BY a;
}
} {9 7 6 8 3 4 2 5 1}
do_test descidx3-3.2 {
execsql {
SELECT i FROM t1 WHERE a=1 AND b>0 AND b<'zzz'
}
} {2 4 3 8 6}
do_test descidx3-3.3 {
execsql {
SELECT i FROM t1 WHERE b>0 AND b<'zzz'
}
} {6 8 3 4 2}
do_test descidx3-3.4 {
execsql {
SELECT i FROM t1 WHERE a=1 AND b>-9999 AND b<x'ffffffff'
}
} {5 2 4 3 8 6 7 9}
do_test descidx3-3.5 {
execsql {
SELECT i FROM t1 WHERE b>-9999 AND b<x'ffffffff'
}
} {9 7 6 8 3 4 2 5}
ifcapable subquery {
# If the subquery capability is not compiled in to the binary, then
# the IN(...) operator is not available. Hence these tests cannot be
# run.
do_test descidx3-4.1 {
execsql {
UPDATE t1 SET a=2 WHERE i<6;
SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz';
}
} {8 6 2 4 3}
do_test descidx3-4.2 {
execsql {
UPDATE t1 SET a=1;
SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz';
}
} {2 4 3 8 6}
do_test descidx3-4.3 {
execsql {
UPDATE t1 SET b=2;
SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz';
}
} {9 7 6 8 3 4 2 5 1}
}
finish_test
+75
View File
@@ -0,0 +1,75 @@
# 2001 October 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing for correct handling of disk full
# errors.
#
# $Id: diskfull.test,v 1.3 2005/09/09 10:46:19 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test diskfull-1.1 {
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(randstr(1000,1000));
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
CREATE INDEX t1i1 ON t1(x);
CREATE TABLE t2 AS SELECT x AS a, x AS b FROM t1;
CREATE INDEX t2i1 ON t2(b);
}
} {}
set sqlite_diskfull_pending 0
integrity_check diskfull-1.2
do_test diskfull-1.3 {
set sqlite_diskfull_pending 1
catchsql {
INSERT INTO t1 SELECT * FROM t1;
}
} {1 {database or disk is full}}
set sqlite_diskfull_pending 0
integrity_check diskfull-1.4
do_test diskfull-1.5 {
set sqlite_diskfull_pending 1
catchsql {
DELETE FROM t1;
}
} {1 {database or disk is full}}
set sqlite_diskfull_pending 0
integrity_check diskfull-1.6
set go 1
set i 0
while {$go} {
incr i
do_test diskfull-2.$i.1 {
set sqlite_diskfull_pending $i
set sqlite_diskfull 0
set r [catchsql {VACUUM}]
if {!$sqlite_diskfull} {
set r {1 {database or disk is full}}
set go 0
}
if {$r=="1 {disk I/O error}"} {
set r {1 {database or disk is full}}
}
set r
} {1 {database or disk is full}}
set sqlite_diskfull_pending 0
db close
sqlite3 db test.db
integrity_check diskfull-2.$i.2
}
finish_test
+57
View File
@@ -0,0 +1,57 @@
# 2005 September 11
#
# 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 regression tests for SQLite library. The
# focus of this script is the DISTINCT modifier on aggregate functions.
#
# $Id: distinctagg.test,v 1.2 2005/09/12 23:03:17 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test distinctagg-1.1 {
execsql {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(1,3,4);
INSERT INTO t1 VALUES(1,3,5);
SELECT count(distinct a),
count(distinct b),
count(distinct c),
count(all a) FROM t1;
}
} {1 2 3 3}
do_test distinctagg-1.2 {
execsql {
SELECT b, count(distinct c) FROM t1 GROUP BY b ORDER BY b
}
} {2 1 3 2}
do_test distinctagg-1.3 {
execsql {
INSERT INTO t1 SELECT a+1, b+3, c+5 FROM t1;
INSERT INTO t1 SELECT a+2, b+6, c+10 FROM t1;
INSERT INTO t1 SELECT a+4, b+12, c+20 FROM t1;
SELECT count(*), count(distinct a), count(distinct b) FROM t1
}
} {24 8 16}
do_test distinctagg-1.4 {
execsql {
SELECT a, count(distinct c) FROM t1 GROUP BY a ORDER BY a
}
} {1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3}
do_test distinctagg-2.1 {
catchsql {
SELECT count(distinct) FROM t1;
}
} {1 {DISTINCT in aggregate must be followed by an expression}}
finish_test
+152
View File
@@ -0,0 +1,152 @@
# 2002 May 24
#
# 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 regression tests for SQLite library. The focus of
# this file is testing the SQLite routines used for converting between the
# various suported unicode encodings (UTF-8, UTF-16, UTF-16le and
# UTF-16be).
#
# $Id: enc.test,v 1.5 2004/11/14 21:56:31 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Skip this test if the build does not support multiple encodings.
#
ifcapable {!utf16} {
finish_test
return
}
proc do_bincmp_test {testname got expect} {
binary scan $expect \c* expectvals
binary scan $got \c* gotvals
do_test $testname [list set dummy $gotvals] $expectvals
}
# $utf16 is a UTF-16 encoded string. Swap each pair of bytes around
# to change the byte-order of the string.
proc swap_byte_order {utf16} {
binary scan $utf16 \c* ints
foreach {a b} $ints {
lappend ints2 $b
lappend ints2 $a
}
return [binary format \c* $ints2]
}
#
# Test that the SQLite routines for converting between UTF encodings
# produce the same results as their TCL counterparts.
#
# $testname is the prefix to be used for the test names.
# $str is a string to use for testing (encoded in UTF-8, as normal for TCL).
#
# The test procedure is:
# 1. Convert the string from UTF-8 to UTF-16le and check that the TCL and
# SQLite routines produce the same results.
#
# 2. Convert the string from UTF-8 to UTF-16be and check that the TCL and
# SQLite routines produce the same results.
#
# 3. Use the SQLite routines to convert the native machine order UTF-16
# representation back to the original UTF-8. Check that the result
# matches the original representation.
#
# 4. Add a byte-order mark to each of the UTF-16 representations and
# check that the SQLite routines can convert them back to UTF-8. For
# byte-order mark info, refer to section 3.10 of the unicode standard.
#
# 5. Take the byte-order marked UTF-16 strings from step 4 and ensure
# that SQLite can convert them both to native byte order UTF-16
# strings, sans BOM.
#
# Coverage:
#
# sqlite_utf8to16be (step 2)
# sqlite_utf8to16le (step 1)
# sqlite_utf16to8 (steps 3, 4)
# sqlite_utf16to16le (step 5)
# sqlite_utf16to16be (step 5)
#
proc test_conversion {testname str} {
# Step 1.
set utf16le_sqlite3 [test_translate $str UTF8 UTF16LE]
set utf16le_tcl [encoding convertto unicode $str]
append utf16le_tcl "\x00\x00"
if { $::tcl_platform(byteOrder)!="littleEndian" } {
set utf16le_tcl [swap_byte_order $utf16le_tcl]
}
do_bincmp_test $testname.1 $utf16le_sqlite3 $utf16le_tcl
set utf16le $utf16le_tcl
# Step 2.
set utf16be_sqlite3 [test_translate $str UTF8 UTF16BE]
set utf16be_tcl [encoding convertto unicode $str]
append utf16be_tcl "\x00\x00"
if { $::tcl_platform(byteOrder)=="littleEndian" } {
set utf16be_tcl [swap_byte_order $utf16be_tcl]
}
do_bincmp_test $testname.2 $utf16be_sqlite3 $utf16be_tcl
set utf16be $utf16be_tcl
# Step 3.
if { $::tcl_platform(byteOrder)=="littleEndian" } {
set utf16 $utf16le
} else {
set utf16 $utf16be
}
set utf8_sqlite3 [test_translate $utf16 UTF16 UTF8]
do_bincmp_test $testname.3 $utf8_sqlite3 [binarize $str]
# Step 4 (little endian).
append utf16le_bom "\xFF\xFE" $utf16le
set utf8_sqlite3 [test_translate $utf16le_bom UTF16 UTF8 1]
do_bincmp_test $testname.4.le $utf8_sqlite3 [binarize $str]
# Step 4 (big endian).
append utf16be_bom "\xFE\xFF" $utf16be
set utf8_sqlite3 [test_translate $utf16be_bom UTF16 UTF8]
do_bincmp_test $testname.4.be $utf8_sqlite3 [binarize $str]
# Step 5 (little endian to little endian).
set utf16_sqlite3 [test_translate $utf16le_bom UTF16LE UTF16LE]
do_bincmp_test $testname.5.le.le $utf16_sqlite3 $utf16le
# Step 5 (big endian to big endian).
set utf16_sqlite3 [test_translate $utf16be_bom UTF16 UTF16BE]
do_bincmp_test $testname.5.be.be $utf16_sqlite3 $utf16be
# Step 5 (big endian to little endian).
set utf16_sqlite3 [test_translate $utf16be_bom UTF16 UTF16LE]
do_bincmp_test $testname.5.be.le $utf16_sqlite3 $utf16le
# Step 5 (little endian to big endian).
set utf16_sqlite3 [test_translate $utf16le_bom UTF16 UTF16BE]
do_bincmp_test $testname.5.le.be $utf16_sqlite3 $utf16be
}
translate_selftest
test_conversion enc-1 "hello world"
test_conversion enc-2 "sqlite"
test_conversion enc-3 ""
test_conversion enc-X "\u0100"
test_conversion enc-4 "\u1234"
test_conversion enc-5 "\u4321abc"
test_conversion enc-6 "\u4321\u1234"
test_conversion enc-7 [string repeat "abcde\u00EF\u00EE\uFFFCabc" 100]
test_conversion enc-8 [string repeat "\u007E\u007F\u0080\u0081" 100]
test_conversion enc-9 [string repeat "\u07FE\u07FF\u0800\u0801\uFFF0" 100]
finish_test
+554
View File
@@ -0,0 +1,554 @@
# 2002 May 24
#
# 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 regression tests for SQLite library. The focus of
# this file is testing the SQLite routines used for converting between the
# various suported unicode encodings (UTF-8, UTF-16, UTF-16le and
# UTF-16be).
#
# $Id: enc2.test,v 1.28 2006/09/23 20:36:03 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If UTF16 support is disabled, ignore the tests in this file
#
ifcapable {!utf16} {
finish_test
return
}
# The rough organisation of tests in this file is:
#
# enc2.1.*: Simple tests with a UTF-8 db.
# enc2.2.*: Simple tests with a UTF-16LE db.
# enc2.3.*: Simple tests with a UTF-16BE db.
# enc2.4.*: Test that attached databases must have the same text encoding
# as the main database.
# enc2.5.*: Test the behaviour of the library when a collation sequence is
# not available for the most desirable text encoding.
# enc2.6.*: Similar test for user functions.
# enc2.7.*: Test that the VerifyCookie opcode protects against assuming the
# wrong text encoding for the database.
# enc2.8.*: Test sqlite3_complete16()
#
db close
# Return the UTF-8 representation of the supplied UTF-16 string $str.
proc utf8 {str} {
# If $str ends in two 0x00 0x00 bytes, knock these off before
# converting to UTF-8 using TCL.
binary scan $str \c* vals
if {[lindex $vals end]==0 && [lindex $vals end-1]==0} {
set str [binary format \c* [lrange $vals 0 end-2]]
}
set r [encoding convertfrom unicode $str]
return $r
}
#
# This proc contains all the tests in this file. It is run
# three times. Each time the file 'test.db' contains a database
# with the following contents:
set dbcontents {
CREATE TABLE t1(a PRIMARY KEY, b, c);
INSERT INTO t1 VALUES('one', 'I', 1);
}
# This proc tests that we can open and manipulate the test.db
# database, and that it is possible to retreive values in
# various text encodings.
#
proc run_test_script {t enc} {
# Open the database and pull out a (the) row.
do_test $t.1 {
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
execsql {SELECT * FROM t1}
} {one I 1}
# Insert some data
do_test $t.2 {
execsql {INSERT INTO t1 VALUES('two', 'II', 2);}
execsql {SELECT * FROM t1}
} {one I 1 two II 2}
# Insert some data
do_test $t.3 {
execsql {
INSERT INTO t1 VALUES('three','III',3);
INSERT INTO t1 VALUES('four','IV',4);
INSERT INTO t1 VALUES('five','V',5);
}
execsql {SELECT * FROM t1}
} {one I 1 two II 2 three III 3 four IV 4 five V 5}
# Use the index
do_test $t.4 {
execsql {
SELECT * FROM t1 WHERE a = 'one';
}
} {one I 1}
do_test $t.5 {
execsql {
SELECT * FROM t1 WHERE a = 'four';
}
} {four IV 4}
ifcapable subquery {
do_test $t.6 {
execsql {
SELECT * FROM t1 WHERE a IN ('one', 'two');
}
} {one I 1 two II 2}
}
# Now check that we can retrieve data in both UTF-16 and UTF-8
do_test $t.7 {
set STMT [sqlite3_prepare $DB "SELECT a FROM t1 WHERE c>3;" -1 TAIL]
sqlite3_step $STMT
sqlite3_column_text $STMT 0
} {four}
do_test $t.8 {
sqlite3_step $STMT
utf8 [sqlite3_column_text16 $STMT 0]
} {five}
do_test $t.9 {
sqlite3_finalize $STMT
} SQLITE_OK
ifcapable vacuum {
execsql VACUUM
}
do_test $t.10 {
db eval {PRAGMA encoding}
} $enc
}
# The three unicode encodings understood by SQLite.
set encodings [list UTF-8 UTF-16le UTF-16be]
set sqlite_os_trace 0
set i 1
foreach enc $encodings {
file delete -force test.db
sqlite3 db test.db
db eval "PRAGMA encoding = \"$enc\""
execsql $dbcontents
do_test enc2-$i.0.1 {
db eval {PRAGMA encoding}
} $enc
do_test enc2-$i.0.2 {
db eval {PRAGMA encoding=UTF8}
db eval {PRAGMA encoding}
} $enc
do_test enc2-$i.0.3 {
db eval {PRAGMA encoding=UTF16le}
db eval {PRAGMA encoding}
} $enc
do_test enc2-$i.0.4 {
db eval {PRAGMA encoding=UTF16be}
db eval {PRAGMA encoding}
} $enc
db close
run_test_script enc2-$i $enc
db close
incr i
}
# Test that it is an error to try to attach a database with a different
# encoding to the main database.
do_test enc2-4.1 {
file delete -force test.db
sqlite3 db test.db
db eval "PRAGMA encoding = 'UTF-8'"
db eval "CREATE TABLE abc(a, b, c);"
} {}
do_test enc2-4.2 {
file delete -force test2.db
sqlite3 db2 test2.db
db2 eval "PRAGMA encoding = 'UTF-16'"
db2 eval "CREATE TABLE abc(a, b, c);"
} {}
do_test enc2-4.3 {
catchsql {
ATTACH 'test2.db' as aux;
}
} {1 {attached databases must use the same text encoding as main database}}
db2 close
db close
# The following tests - enc2-5.* - test that SQLite selects the correct
# collation sequence when more than one is available.
set ::values [list one two three four five]
set ::test_collate_enc INVALID
proc test_collate {enc lhs rhs} {
set ::test_collate_enc $enc
set l [lsearch -exact $::values $lhs]
set r [lsearch -exact $::values $rhs]
set res [expr $l - $r]
# puts "enc=$enc lhs=$lhs/$l rhs=$rhs/$r res=$res"
return $res
}
file delete -force test.db
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-5.0 {
execsql {
CREATE TABLE t5(a);
INSERT INTO t5 VALUES('one');
INSERT INTO t5 VALUES('two');
INSERT INTO t5 VALUES('five');
INSERT INTO t5 VALUES('three');
INSERT INTO t5 VALUES('four');
}
} {}
do_test enc2-5.1 {
add_test_collate $DB 1 1 1
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate;}]
lappend res $::test_collate_enc
} {one two three four five UTF-8}
do_test enc2-5.2 {
add_test_collate $DB 0 1 0
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-16LE}
do_test enc2-5.3 {
add_test_collate $DB 0 0 1
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-16BE}
db close
file delete -force test.db
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
execsql {pragma encoding = 'UTF-16LE'}
do_test enc2-5.4 {
execsql {
CREATE TABLE t5(a);
INSERT INTO t5 VALUES('one');
INSERT INTO t5 VALUES('two');
INSERT INTO t5 VALUES('five');
INSERT INTO t5 VALUES('three');
INSERT INTO t5 VALUES('four');
}
} {}
do_test enc2-5.5 {
add_test_collate $DB 1 1 1
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-16LE}
do_test enc2-5.6 {
add_test_collate $DB 1 0 1
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-16BE}
do_test enc2-5.7 {
add_test_collate $DB 1 0 0
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-8}
db close
file delete -force test.db
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
execsql {pragma encoding = 'UTF-16BE'}
do_test enc2-5.8 {
execsql {
CREATE TABLE t5(a);
INSERT INTO t5 VALUES('one');
INSERT INTO t5 VALUES('two');
INSERT INTO t5 VALUES('five');
INSERT INTO t5 VALUES('three');
INSERT INTO t5 VALUES('four');
}
} {}
do_test enc2-5.9 {
add_test_collate $DB 1 1 1
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-16BE}
do_test enc2-5.10 {
add_test_collate $DB 1 1 0
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-16LE}
do_test enc2-5.11 {
add_test_collate $DB 1 0 0
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate}]
lappend res $::test_collate_enc
} {one two three four five UTF-8}
# Also test that a UTF-16 collation factory works.
do_test enc2-5-12 {
add_test_collate $DB 0 0 0
catchsql {
SELECT * FROM t5 ORDER BY 1 COLLATE test_collate
}
} {1 {no such collation sequence: test_collate}}
do_test enc2-5.13 {
add_test_collate_needed $DB
set res [execsql {SELECT * FROM t5 ORDER BY 1 COLLATE test_collate; }]
lappend res $::test_collate_enc
} {one two three four five UTF-16BE}
do_test enc2-5.14 {
set ::sqlite_last_needed_collation
} test_collate
db close
file delete -force test.db
do_test enc2-5.15 {
sqlite3 db test.db; set ::DB [sqlite3_connection_pointer db]
add_test_collate_needed $::DB
set ::sqlite_last_needed_collation
} {}
do_test enc2-5.16 {
execsql {CREATE TABLE t1(a varchar collate test_collate);}
} {}
do_test enc2-5.17 {
set ::sqlite_last_needed_collation
} {test_collate}
# The following tests - enc2-6.* - test that SQLite selects the correct
# user function when more than one is available.
proc test_function {enc arg} {
return "$enc $arg"
}
db close
file delete -force test.db
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
execsql {pragma encoding = 'UTF-8'}
do_test enc2-6.0 {
execsql {
CREATE TABLE t5(a);
INSERT INTO t5 VALUES('one');
}
} {}
do_test enc2-6.1 {
add_test_function $DB 1 1 1
execsql {
SELECT test_function('sqlite')
}
} {{UTF-8 sqlite}}
db close
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-6.2 {
add_test_function $DB 0 1 0
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16LE sqlite}}
db close
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-6.3 {
add_test_function $DB 0 0 1
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16BE sqlite}}
db close
file delete -force test.db
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
execsql {pragma encoding = 'UTF-16LE'}
do_test enc2-6.3 {
execsql {
CREATE TABLE t5(a);
INSERT INTO t5 VALUES('sqlite');
}
} {}
do_test enc2-6.4 {
add_test_function $DB 1 1 1
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16LE sqlite}}
db close
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-6.5 {
add_test_function $DB 0 1 0
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16LE sqlite}}
db close
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-6.6 {
add_test_function $DB 0 0 1
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16BE sqlite}}
db close
file delete -force test.db
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
execsql {pragma encoding = 'UTF-16BE'}
do_test enc2-6.7 {
execsql {
CREATE TABLE t5(a);
INSERT INTO t5 VALUES('sqlite');
}
} {}
do_test enc2-6.8 {
add_test_function $DB 1 1 1
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16BE sqlite}}
db close
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-6.9 {
add_test_function $DB 0 1 0
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16LE sqlite}}
db close
sqlite3 db test.db; set DB [sqlite3_connection_pointer db]
do_test enc2-6.10 {
add_test_function $DB 0 0 1
execsql {
SELECT test_function('sqlite')
}
} {{UTF-16BE sqlite}}
db close
file delete -force test.db
# The following tests - enc2-7.* - function as follows:
#
# 1: Open an empty database file assuming UTF-16 encoding.
# 2: Open the same database with a different handle assuming UTF-8. Create
# a table using this handle.
# 3: Read the sqlite_master table from the first handle.
# 4: Ensure the first handle recognises the database encoding is UTF-8.
#
do_test enc2-7.1 {
sqlite3 db test.db
execsql {
PRAGMA encoding = 'UTF-16';
SELECT * FROM sqlite_master;
}
} {}
do_test enc2-7.2 {
set enc [execsql {
PRAGMA encoding;
}]
string range $enc 0 end-2 ;# Chop off the "le" or "be"
} {UTF-16}
do_test enc2-7.3 {
sqlite3 db2 test.db
execsql {
PRAGMA encoding = 'UTF-8';
CREATE TABLE abc(a, b, c);
} db2
} {}
do_test enc2-7.4 {
execsql {
SELECT * FROM sqlite_master;
}
} "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}"
do_test enc2-7.5 {
execsql {
PRAGMA encoding;
}
} {UTF-8}
db close
db2 close
proc utf16 {utf8} {
set utf16 [encoding convertto unicode $utf8]
append utf16 "\x00\x00"
return $utf16
}
ifcapable {complete} {
do_test enc2-8.1 {
sqlite3_complete16 [utf16 "SELECT * FROM t1;"]
} {1}
do_test enc2-8.2 {
sqlite3_complete16 [utf16 "SELECT * FROM"]
} {0}
}
# Test that the encoding of an empty database may still be set after the
# (empty) schema has been initialized.
file delete -force test.db
do_test enc2-9.1 {
sqlite3 db test.db
execsql {
PRAGMA encoding = 'UTF-8';
PRAGMA encoding;
}
} {UTF-8}
do_test enc2-9.2 {
sqlite3 db test.db
execsql {
PRAGMA encoding = 'UTF-16le';
PRAGMA encoding;
}
} {UTF-16le}
do_test enc2-9.3 {
sqlite3 db test.db
execsql {
SELECT * FROM sqlite_master;
PRAGMA encoding = 'UTF-8';
PRAGMA encoding;
}
} {UTF-8}
do_test enc2-9.4 {
sqlite3 db test.db
execsql {
PRAGMA encoding = 'UTF-16le';
CREATE TABLE abc(a, b, c);
PRAGMA encoding;
}
} {UTF-16le}
do_test enc2-9.5 {
sqlite3 db test.db
execsql {
PRAGMA encoding = 'UTF-8';
PRAGMA encoding;
}
} {UTF-16le}
# Ticket #1987.
# Disallow encoding changes once the encoding has been set.
#
do_test enc2-10.1 {
db close
file delete -force test.db test.db-journal
sqlite3 db test.db
db eval {
PRAGMA encoding=UTF16;
CREATE TABLE t1(a);
PRAGMA encoding=UTF8;
CREATE TABLE t2(b);
}
db close
sqlite3 db test.db
db eval {
SELECT name FROM sqlite_master
}
} {t1 t2}
finish_test
+71
View File
@@ -0,0 +1,71 @@
# 2002 May 24
#
# 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 regression tests for SQLite library.
#
# The focus of this file is testing of the proper handling of conversions
# to the native text representation.
#
# $Id: enc3.test,v 1.5 2006/01/12 19:42:41 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {utf16} {
do_test enc3-1.1 {
execsql {
PRAGMA encoding=utf16le;
PRAGMA encoding;
}
} {UTF-16le}
}
do_test enc3-1.2 {
execsql {
CREATE TABLE t1(x,y);
INSERT INTO t1 VALUES('abc''123',5);
SELECT * FROM t1
}
} {abc'123 5}
do_test enc3-1.3 {
execsql {
SELECT quote(x) || ' ' || quote(y) FROM t1
}
} {{'abc''123' 5}}
ifcapable {bloblit} {
do_test enc3-1.4 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES(x'616263646566',NULL);
SELECT * FROM t1
}
} {abcdef {}}
do_test enc3-1.5 {
execsql {
SELECT quote(x) || ' ' || quote(y) FROM t1
}
} {{X'616263646566' NULL}}
}
ifcapable {bloblit && utf16} {
do_test enc3-2.1 {
execsql {
PRAGMA encoding
}
} {UTF-16le}
do_test enc3-2.2 {
execsql {
CREATE TABLE t2(a);
INSERT INTO t2 VALUES(x'61006200630064006500');
SELECT CAST(a AS text) FROM t2 WHERE a LIKE 'abc%';
}
} {abcde}
}
finish_test
+654
View File
@@ -0,0 +1,654 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing expressions.
#
# $Id: expr.test,v 1.52 2006/09/01 15:49:06 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table to work with.
#
execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)}
execsql {INSERT INTO test1 VALUES(1,2,1.1,2.2,'hello','world')}
proc test_expr {name settings expr result} {
do_test $name [format {
execsql {BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK;}
} $settings $expr] $result
}
test_expr expr-1.1 {i1=10, i2=20} {i1+i2} 30
test_expr expr-1.2 {i1=10, i2=20} {i1-i2} -10
test_expr expr-1.3 {i1=10, i2=20} {i1*i2} 200
test_expr expr-1.4 {i1=10, i2=20} {i1/i2} 0
test_expr expr-1.5 {i1=10, i2=20} {i2/i1} 2
test_expr expr-1.6 {i1=10, i2=20} {i2<i1} 0
test_expr expr-1.7 {i1=10, i2=20} {i2<=i1} 0
test_expr expr-1.8 {i1=10, i2=20} {i2>i1} 1
test_expr expr-1.9 {i1=10, i2=20} {i2>=i1} 1
test_expr expr-1.10 {i1=10, i2=20} {i2!=i1} 1
test_expr expr-1.11 {i1=10, i2=20} {i2=i1} 0
test_expr expr-1.12 {i1=10, i2=20} {i2<>i1} 1
test_expr expr-1.13 {i1=10, i2=20} {i2==i1} 0
test_expr expr-1.14 {i1=20, i2=20} {i2<i1} 0
test_expr expr-1.15 {i1=20, i2=20} {i2<=i1} 1
test_expr expr-1.16 {i1=20, i2=20} {i2>i1} 0
test_expr expr-1.17 {i1=20, i2=20} {i2>=i1} 1
test_expr expr-1.18 {i1=20, i2=20} {i2!=i1} 0
test_expr expr-1.19 {i1=20, i2=20} {i2=i1} 1
test_expr expr-1.20 {i1=20, i2=20} {i2<>i1} 0
test_expr expr-1.21 {i1=20, i2=20} {i2==i1} 1
test_expr expr-1.22 {i1=1, i2=2, r1=3.0} {i1+i2*r1} {7.0}
test_expr expr-1.23 {i1=1, i2=2, r1=3.0} {(i1+i2)*r1} {9.0}
test_expr expr-1.24 {i1=1, i2=2} {min(i1,i2,i1+i2,i1-i2)} {-1}
test_expr expr-1.25 {i1=1, i2=2} {max(i1,i2,i1+i2,i1-i2)} {3}
test_expr expr-1.26 {i1=1, i2=2} {max(i1,i2,i1+i2,i1-i2)} {3}
test_expr expr-1.27 {i1=1, i2=2} {i1==1 AND i2=2} {1}
test_expr expr-1.28 {i1=1, i2=2} {i1=2 AND i2=1} {0}
test_expr expr-1.29 {i1=1, i2=2} {i1=1 AND i2=1} {0}
test_expr expr-1.30 {i1=1, i2=2} {i1=2 AND i2=2} {0}
test_expr expr-1.31 {i1=1, i2=2} {i1==1 OR i2=2} {1}
test_expr expr-1.32 {i1=1, i2=2} {i1=2 OR i2=1} {0}
test_expr expr-1.33 {i1=1, i2=2} {i1=1 OR i2=1} {1}
test_expr expr-1.34 {i1=1, i2=2} {i1=2 OR i2=2} {1}
test_expr expr-1.35 {i1=1, i2=2} {i1-i2=-1} {1}
test_expr expr-1.36 {i1=1, i2=0} {not i1} {0}
test_expr expr-1.37 {i1=1, i2=0} {not i2} {1}
test_expr expr-1.38 {i1=1} {-i1} {-1}
test_expr expr-1.39 {i1=1} {+i1} {1}
test_expr expr-1.40 {i1=1, i2=2} {+(i2+i1)} {3}
test_expr expr-1.41 {i1=1, i2=2} {-(i2+i1)} {-3}
test_expr expr-1.42 {i1=1, i2=2} {i1|i2} {3}
test_expr expr-1.42b {i1=1, i2=2} {4|2} {6}
test_expr expr-1.43 {i1=1, i2=2} {i1&i2} {0}
test_expr expr-1.43b {i1=1, i2=2} {4&5} {4}
test_expr expr-1.44 {i1=1} {~i1} {-2}
test_expr expr-1.45 {i1=1, i2=3} {i1<<i2} {8}
test_expr expr-1.46 {i1=32, i2=3} {i1>>i2} {4}
test_expr expr-1.47 {i1=9999999999, i2=8888888888} {i1<i2} 0
test_expr expr-1.48 {i1=9999999999, i2=8888888888} {i1=i2} 0
test_expr expr-1.49 {i1=9999999999, i2=8888888888} {i1>i2} 1
test_expr expr-1.50 {i1=99999999999, i2=99999999998} {i1<i2} 0
test_expr expr-1.51 {i1=99999999999, i2=99999999998} {i1=i2} 0
test_expr expr-1.52 {i1=99999999999, i2=99999999998} {i1>i2} 1
test_expr expr-1.53 {i1=099999999999, i2=99999999999} {i1<i2} 0
test_expr expr-1.54 {i1=099999999999, i2=99999999999} {i1=i2} 1
test_expr expr-1.55 {i1=099999999999, i2=99999999999} {i1>i2} 0
test_expr expr-1.56 {i1=25, i2=11} {i1%i2} 3
test_expr expr-1.58 {i1=NULL, i2=1} {coalesce(i1+i2,99)} 99
test_expr expr-1.59 {i1=1, i2=NULL} {coalesce(i1+i2,99)} 99
test_expr expr-1.60 {i1=NULL, i2=NULL} {coalesce(i1+i2,99)} 99
test_expr expr-1.61 {i1=NULL, i2=1} {coalesce(i1-i2,99)} 99
test_expr expr-1.62 {i1=1, i2=NULL} {coalesce(i1-i2,99)} 99
test_expr expr-1.63 {i1=NULL, i2=NULL} {coalesce(i1-i2,99)} 99
test_expr expr-1.64 {i1=NULL, i2=1} {coalesce(i1*i2,99)} 99
test_expr expr-1.65 {i1=1, i2=NULL} {coalesce(i1*i2,99)} 99
test_expr expr-1.66 {i1=NULL, i2=NULL} {coalesce(i1*i2,99)} 99
test_expr expr-1.67 {i1=NULL, i2=1} {coalesce(i1/i2,99)} 99
test_expr expr-1.68 {i1=1, i2=NULL} {coalesce(i1/i2,99)} 99
test_expr expr-1.69 {i1=NULL, i2=NULL} {coalesce(i1/i2,99)} 99
test_expr expr-1.70 {i1=NULL, i2=1} {coalesce(i1<i2,99)} 99
test_expr expr-1.71 {i1=1, i2=NULL} {coalesce(i1>i2,99)} 99
test_expr expr-1.72 {i1=NULL, i2=NULL} {coalesce(i1<=i2,99)} 99
test_expr expr-1.73 {i1=NULL, i2=1} {coalesce(i1>=i2,99)} 99
test_expr expr-1.74 {i1=1, i2=NULL} {coalesce(i1!=i2,99)} 99
test_expr expr-1.75 {i1=NULL, i2=NULL} {coalesce(i1==i2,99)} 99
test_expr expr-1.76 {i1=NULL, i2=NULL} {coalesce(not i1,99)} 99
test_expr expr-1.77 {i1=NULL, i2=NULL} {coalesce(-i1,99)} 99
test_expr expr-1.78 {i1=NULL, i2=NULL} {coalesce(i1 IS NULL AND i2=5,99)} 99
test_expr expr-1.79 {i1=NULL, i2=NULL} {coalesce(i1 IS NULL OR i2=5,99)} 1
test_expr expr-1.80 {i1=NULL, i2=NULL} {coalesce(i1=5 AND i2 IS NULL,99)} 99
test_expr expr-1.81 {i1=NULL, i2=NULL} {coalesce(i1=5 OR i2 IS NULL,99)} 1
test_expr expr-1.82 {i1=NULL, i2=3} {coalesce(min(i1,i2,1),99)} 99
test_expr expr-1.83 {i1=NULL, i2=3} {coalesce(max(i1,i2,1),99)} 99
test_expr expr-1.84 {i1=3, i2=NULL} {coalesce(min(i1,i2,1),99)} 99
test_expr expr-1.85 {i1=3, i2=NULL} {coalesce(max(i1,i2,1),99)} 99
test_expr expr-1.86 {i1=3, i2=8} {5 between i1 and i2} 1
test_expr expr-1.87 {i1=3, i2=8} {5 not between i1 and i2} 0
test_expr expr-1.88 {i1=3, i2=8} {55 between i1 and i2} 0
test_expr expr-1.89 {i1=3, i2=8} {55 not between i1 and i2} 1
test_expr expr-1.90 {i1=3, i2=NULL} {5 between i1 and i2} {{}}
test_expr expr-1.91 {i1=3, i2=NULL} {5 not between i1 and i2} {{}}
test_expr expr-1.92 {i1=3, i2=NULL} {2 between i1 and i2} 0
test_expr expr-1.93 {i1=3, i2=NULL} {2 not between i1 and i2} 1
test_expr expr-1.94 {i1=NULL, i2=8} {2 between i1 and i2} {{}}
test_expr expr-1.95 {i1=NULL, i2=8} {2 not between i1 and i2} {{}}
test_expr expr-1.94 {i1=NULL, i2=8} {55 between i1 and i2} 0
test_expr expr-1.95 {i1=NULL, i2=8} {55 not between i1 and i2} 1
test_expr expr-1.96 {i1=NULL, i2=3} {coalesce(i1<<i2,99)} 99
test_expr expr-1.97 {i1=32, i2=NULL} {coalesce(i1>>i2,99)} 99
test_expr expr-1.98 {i1=NULL, i2=NULL} {coalesce(i1|i2,99)} 99
test_expr expr-1.99 {i1=32, i2=NULL} {coalesce(i1&i2,99)} 99
test_expr expr-1.100 {i1=1, i2=''} {i1=i2} 0
test_expr expr-1.101 {i1=0, i2=''} {i1=i2} 0
# Check for proper handling of 64-bit integer values.
#
test_expr expr-1.102 {i1=40, i2=1} {i2<<i1} 1099511627776
test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57
test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11
test_expr expr-2.3 {r1=1.23, r2=2.34} {r1*r2} 2.8782
set tcl_precision 15
test_expr expr-2.4 {r1=1.23, r2=2.34} {r1/r2} 0.525641025641026
test_expr expr-2.5 {r1=1.23, r2=2.34} {r2/r1} 1.90243902439024
test_expr expr-2.6 {r1=1.23, r2=2.34} {r2<r1} 0
test_expr expr-2.7 {r1=1.23, r2=2.34} {r2<=r1} 0
test_expr expr-2.8 {r1=1.23, r2=2.34} {r2>r1} 1
test_expr expr-2.9 {r1=1.23, r2=2.34} {r2>=r1} 1
test_expr expr-2.10 {r1=1.23, r2=2.34} {r2!=r1} 1
test_expr expr-2.11 {r1=1.23, r2=2.34} {r2=r1} 0
test_expr expr-2.12 {r1=1.23, r2=2.34} {r2<>r1} 1
test_expr expr-2.13 {r1=1.23, r2=2.34} {r2==r1} 0
test_expr expr-2.14 {r1=2.34, r2=2.34} {r2<r1} 0
test_expr expr-2.15 {r1=2.34, r2=2.34} {r2<=r1} 1
test_expr expr-2.16 {r1=2.34, r2=2.34} {r2>r1} 0
test_expr expr-2.17 {r1=2.34, r2=2.34} {r2>=r1} 1
test_expr expr-2.18 {r1=2.34, r2=2.34} {r2!=r1} 0
test_expr expr-2.19 {r1=2.34, r2=2.34} {r2=r1} 1
test_expr expr-2.20 {r1=2.34, r2=2.34} {r2<>r1} 0
test_expr expr-2.21 {r1=2.34, r2=2.34} {r2==r1} 1
test_expr expr-2.22 {r1=1.23, r2=2.34} {min(r1,r2,r1+r2,r1-r2)} {-1.11}
test_expr expr-2.23 {r1=1.23, r2=2.34} {max(r1,r2,r1+r2,r1-r2)} {3.57}
test_expr expr-2.24 {r1=25.0, r2=11.0} {r1%r2} 3.0
test_expr expr-2.25 {r1=1.23, r2=NULL} {coalesce(r1+r2,99.0)} 99.0
test_expr expr-3.1 {t1='abc', t2='xyz'} {t1<t2} 1
test_expr expr-3.2 {t1='xyz', t2='abc'} {t1<t2} 0
test_expr expr-3.3 {t1='abc', t2='abc'} {t1<t2} 0
test_expr expr-3.4 {t1='abc', t2='xyz'} {t1<=t2} 1
test_expr expr-3.5 {t1='xyz', t2='abc'} {t1<=t2} 0
test_expr expr-3.6 {t1='abc', t2='abc'} {t1<=t2} 1
test_expr expr-3.7 {t1='abc', t2='xyz'} {t1>t2} 0
test_expr expr-3.8 {t1='xyz', t2='abc'} {t1>t2} 1
test_expr expr-3.9 {t1='abc', t2='abc'} {t1>t2} 0
test_expr expr-3.10 {t1='abc', t2='xyz'} {t1>=t2} 0
test_expr expr-3.11 {t1='xyz', t2='abc'} {t1>=t2} 1
test_expr expr-3.12 {t1='abc', t2='abc'} {t1>=t2} 1
test_expr expr-3.13 {t1='abc', t2='xyz'} {t1=t2} 0
test_expr expr-3.14 {t1='xyz', t2='abc'} {t1=t2} 0
test_expr expr-3.15 {t1='abc', t2='abc'} {t1=t2} 1
test_expr expr-3.16 {t1='abc', t2='xyz'} {t1==t2} 0
test_expr expr-3.17 {t1='xyz', t2='abc'} {t1==t2} 0
test_expr expr-3.18 {t1='abc', t2='abc'} {t1==t2} 1
test_expr expr-3.19 {t1='abc', t2='xyz'} {t1<>t2} 1
test_expr expr-3.20 {t1='xyz', t2='abc'} {t1<>t2} 1
test_expr expr-3.21 {t1='abc', t2='abc'} {t1<>t2} 0
test_expr expr-3.22 {t1='abc', t2='xyz'} {t1!=t2} 1
test_expr expr-3.23 {t1='xyz', t2='abc'} {t1!=t2} 1
test_expr expr-3.24 {t1='abc', t2='abc'} {t1!=t2} 0
test_expr expr-3.25 {t1=NULL, t2='hi'} {t1 isnull} 1
test_expr expr-3.25b {t1=NULL, t2='hi'} {t1 is null} 1
test_expr expr-3.26 {t1=NULL, t2='hi'} {t2 isnull} 0
test_expr expr-3.27 {t1=NULL, t2='hi'} {t1 notnull} 0
test_expr expr-3.28 {t1=NULL, t2='hi'} {t2 notnull} 1
test_expr expr-3.28b {t1=NULL, t2='hi'} {t2 is not null} 1
test_expr expr-3.29 {t1='xyz', t2='abc'} {t1||t2} {xyzabc}
test_expr expr-3.30 {t1=NULL, t2='abc'} {t1||t2} {{}}
test_expr expr-3.31 {t1='xyz', t2=NULL} {t1||t2} {{}}
test_expr expr-3.32 {t1='xyz', t2='abc'} {t1||' hi '||t2} {{xyz hi abc}}
test_expr epxr-3.33 {t1='abc', t2=NULL} {coalesce(t1<t2,99)} 99
test_expr epxr-3.34 {t1='abc', t2=NULL} {coalesce(t2<t1,99)} 99
test_expr epxr-3.35 {t1='abc', t2=NULL} {coalesce(t1>t2,99)} 99
test_expr epxr-3.36 {t1='abc', t2=NULL} {coalesce(t2>t1,99)} 99
test_expr epxr-3.37 {t1='abc', t2=NULL} {coalesce(t1<=t2,99)} 99
test_expr epxr-3.38 {t1='abc', t2=NULL} {coalesce(t2<=t1,99)} 99
test_expr epxr-3.39 {t1='abc', t2=NULL} {coalesce(t1>=t2,99)} 99
test_expr epxr-3.40 {t1='abc', t2=NULL} {coalesce(t2>=t1,99)} 99
test_expr epxr-3.41 {t1='abc', t2=NULL} {coalesce(t1==t2,99)} 99
test_expr epxr-3.42 {t1='abc', t2=NULL} {coalesce(t2==t1,99)} 99
test_expr epxr-3.43 {t1='abc', t2=NULL} {coalesce(t1!=t2,99)} 99
test_expr epxr-3.44 {t1='abc', t2=NULL} {coalesce(t2!=t1,99)} 99
test_expr expr-4.1 {t1='abc', t2='Abc'} {t1<t2} 0
test_expr expr-4.2 {t1='abc', t2='Abc'} {t1>t2} 1
test_expr expr-4.3 {t1='abc', t2='Bbc'} {t1<t2} 0
test_expr expr-4.4 {t1='abc', t2='Bbc'} {t1>t2} 1
test_expr expr-4.5 {t1='0', t2='0.0'} {t1==t2} 0
test_expr expr-4.6 {t1='0.000', t2='0.0'} {t1==t2} 0
test_expr expr-4.7 {t1=' 0.000', t2=' 0.0'} {t1==t2} 0
test_expr expr-4.8 {t1='0.0', t2='abc'} {t1<t2} 1
test_expr expr-4.9 {t1='0.0', t2='abc'} {t1==t2} 0
test_expr expr-4.10 {r1='0.0', r2='abc'} {r1>r2} 0
test_expr expr-4.11 {r1='abc', r2='Abc'} {r1<r2} 0
test_expr expr-4.12 {r1='abc', r2='Abc'} {r1>r2} 1
test_expr expr-4.13 {r1='abc', r2='Bbc'} {r1<r2} 0
test_expr expr-4.14 {r1='abc', r2='Bbc'} {r1>r2} 1
test_expr expr-4.15 {r1='0', r2='0.0'} {r1==r2} 1
test_expr expr-4.16 {r1='0.000', r2='0.0'} {r1==r2} 1
test_expr expr-4.17 {r1=' 0.000', r2=' 0.0'} {r1==r2} 0
test_expr expr-4.18 {r1='0.0', r2='abc'} {r1<r2} 1
test_expr expr-4.19 {r1='0.0', r2='abc'} {r1==r2} 0
test_expr expr-4.20 {r1='0.0', r2='abc'} {r1>r2} 0
# CSL is true if LIKE is case sensitive and false if not.
# NCSL is the opposite. Use these variables as the result
# on operations where case makes a difference.
set CSL $sqlite_options(casesensitivelike)
set NCSL [expr {!$CSL}]
test_expr expr-5.1 {t1='abc', t2='xyz'} {t1 LIKE t2} 0
test_expr expr-5.2a {t1='abc', t2='abc'} {t1 LIKE t2} 1
test_expr expr-5.2b {t1='abc', t2='ABC'} {t1 LIKE t2} $NCSL
test_expr expr-5.3a {t1='abc', t2='a_c'} {t1 LIKE t2} 1
test_expr expr-5.3b {t1='abc', t2='A_C'} {t1 LIKE t2} $NCSL
test_expr expr-5.4 {t1='abc', t2='abc_'} {t1 LIKE t2} 0
test_expr expr-5.5a {t1='abc', t2='a%c'} {t1 LIKE t2} 1
test_expr expr-5.5b {t1='abc', t2='A%C'} {t1 LIKE t2} $NCSL
test_expr expr-5.5c {t1='abdc', t2='a%c'} {t1 LIKE t2} 1
test_expr expr-5.5d {t1='ac', t2='a%c'} {t1 LIKE t2} 1
test_expr expr-5.5e {t1='ac', t2='A%C'} {t1 LIKE t2} $NCSL
test_expr expr-5.6a {t1='abxyzzyc', t2='a%c'} {t1 LIKE t2} 1
test_expr expr-5.6b {t1='abxyzzyc', t2='A%C'} {t1 LIKE t2} $NCSL
test_expr expr-5.7a {t1='abxyzzy', t2='a%c'} {t1 LIKE t2} 0
test_expr expr-5.7b {t1='abxyzzy', t2='A%C'} {t1 LIKE t2} 0
test_expr expr-5.8a {t1='abxyzzycx', t2='a%c'} {t1 LIKE t2} 0
test_expr expr-5.8b {t1='abxyzzycy', t2='a%cx'} {t1 LIKE t2} 0
test_expr expr-5.8c {t1='abxyzzycx', t2='A%C'} {t1 LIKE t2} 0
test_expr expr-5.8d {t1='abxyzzycy', t2='A%CX'} {t1 LIKE t2} 0
test_expr expr-5.9a {t1='abc', t2='a%_c'} {t1 LIKE t2} 1
test_expr expr-5.9b {t1='ac', t2='a%_c'} {t1 LIKE t2} 0
test_expr expr-5.9c {t1='abc', t2='A%_C'} {t1 LIKE t2} $NCSL
test_expr expr-5.9d {t1='ac', t2='A%_C'} {t1 LIKE t2} 0
test_expr expr-5.10a {t1='abxyzzyc', t2='a%_c'} {t1 LIKE t2} 1
test_expr expr-5.10b {t1='abxyzzyc', t2='A%_C'} {t1 LIKE t2} $NCSL
test_expr expr-5.11 {t1='abc', t2='xyz'} {t1 NOT LIKE t2} 1
test_expr expr-5.12a {t1='abc', t2='abc'} {t1 NOT LIKE t2} 0
test_expr expr-5.12b {t1='abc', t2='ABC'} {t1 NOT LIKE t2} $CSL
# The following tests only work on versions of TCL that support Unicode
#
if {"\u1234"!="u1234"} {
test_expr expr-5.13a "t1='a\u0080c', t2='a_c'" {t1 LIKE t2} 1
test_expr expr-5.13b "t1='a\u0080c', t2='A_C'" {t1 LIKE t2} $NCSL
test_expr expr-5.14a "t1='a\u07FFc', t2='a_c'" {t1 LIKE t2} 1
test_expr expr-5.14b "t1='a\u07FFc', t2='A_C'" {t1 LIKE t2} $NCSL
test_expr expr-5.15a "t1='a\u0800c', t2='a_c'" {t1 LIKE t2} 1
test_expr expr-5.15b "t1='a\u0800c', t2='A_C'" {t1 LIKE t2} $NCSL
test_expr expr-5.16a "t1='a\uFFFFc', t2='a_c'" {t1 LIKE t2} 1
test_expr expr-5.16b "t1='a\uFFFFc', t2='A_C'" {t1 LIKE t2} $NCSL
test_expr expr-5.17 "t1='a\u0080', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.18 "t1='a\u07FF', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.19 "t1='a\u0800', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.20 "t1='a\uFFFF', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.21a "t1='ax\uABCD', t2='a_\uABCD'" {t1 LIKE t2} 1
test_expr expr-5.21b "t1='ax\uABCD', t2='A_\uABCD'" {t1 LIKE t2} $NCSL
test_expr expr-5.22a "t1='ax\u1234', t2='a%\u1234'" {t1 LIKE t2} 1
test_expr expr-5.22b "t1='ax\u1234', t2='A%\u1234'" {t1 LIKE t2} $NCSL
test_expr expr-5.23a "t1='ax\uFEDC', t2='a_%'" {t1 LIKE t2} 1
test_expr expr-5.23b "t1='ax\uFEDC', t2='A_%'" {t1 LIKE t2} $NCSL
test_expr expr-5.24a "t1='ax\uFEDCy\uFEDC', t2='a%\uFEDC'" {t1 LIKE t2} 1
test_expr expr-5.24b "t1='ax\uFEDCy\uFEDC', t2='A%\uFEDC'" {t1 LIKE t2} $NCSL
}
test_expr expr-5.54 {t1='abc', t2=NULL} {t1 LIKE t2} {{}}
test_expr expr-5.55 {t1='abc', t2=NULL} {t1 NOT LIKE t2} {{}}
test_expr expr-5.56 {t1='abc', t2=NULL} {t2 LIKE t1} {{}}
test_expr expr-5.57 {t1='abc', t2=NULL} {t2 NOT LIKE t1} {{}}
# LIKE expressions that use ESCAPE characters.
test_expr expr-5.58a {t1='abc', t2='a_c'} {t1 LIKE t2 ESCAPE '7'} 1
test_expr expr-5.58b {t1='abc', t2='A_C'} {t1 LIKE t2 ESCAPE '7'} $NCSL
test_expr expr-5.59a {t1='a_c', t2='a7_c'} {t1 LIKE t2 ESCAPE '7'} 1
test_expr expr-5.59b {t1='a_c', t2='A7_C'} {t1 LIKE t2 ESCAPE '7'} $NCSL
test_expr expr-5.60a {t1='abc', t2='a7_c'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.60b {t1='abc', t2='A7_C'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.61a {t1='a7Xc', t2='a7_c'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.61b {t1='a7Xc', t2='A7_C'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.62a {t1='abcde', t2='a%e'} {t1 LIKE t2 ESCAPE '7'} 1
test_expr expr-5.62b {t1='abcde', t2='A%E'} {t1 LIKE t2 ESCAPE '7'} $NCSL
test_expr expr-5.63a {t1='abcde', t2='a7%e'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.63b {t1='abcde', t2='A7%E'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.64a {t1='a7cde', t2='a7%e'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.64b {t1='a7cde', t2='A7%E'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.65a {t1='a7cde', t2='a77%e'} {t1 LIKE t2 ESCAPE '7'} 1
test_expr expr-5.65b {t1='a7cde', t2='A77%E'} {t1 LIKE t2 ESCAPE '7'} $NCSL
test_expr expr-5.66a {t1='abc7', t2='a%77'} {t1 LIKE t2 ESCAPE '7'} 1
test_expr expr-5.66b {t1='abc7', t2='A%77'} {t1 LIKE t2 ESCAPE '7'} $NCSL
test_expr expr-5.67a {t1='abc_', t2='a%7_'} {t1 LIKE t2 ESCAPE '7'} 1
test_expr expr-5.67b {t1='abc_', t2='A%7_'} {t1 LIKE t2 ESCAPE '7'} $NCSL
test_expr expr-5.68a {t1='abc7', t2='a%7_'} {t1 LIKE t2 ESCAPE '7'} 0
test_expr expr-5.68b {t1='abc7', t2='A%7_'} {t1 LIKE t2 ESCAPE '7'} 0
# These are the same test as the block above, but using a multi-byte
# character as the escape character.
if {"\u1234"!="u1234"} {
test_expr expr-5.69a "t1='abc', t2='a_c'" \
"t1 LIKE t2 ESCAPE '\u1234'" 1
test_expr expr-5.69b "t1='abc', t2='A_C'" \
"t1 LIKE t2 ESCAPE '\u1234'" $NCSL
test_expr expr-5.70a "t1='a_c', t2='a\u1234_c'" \
"t1 LIKE t2 ESCAPE '\u1234'" 1
test_expr expr-5.70b "t1='a_c', t2='A\u1234_C'" \
"t1 LIKE t2 ESCAPE '\u1234'" $NCSL
test_expr expr-5.71a "t1='abc', t2='a\u1234_c'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.71b "t1='abc', t2='A\u1234_C'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.72a "t1='a\u1234Xc', t2='a\u1234_c'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.72b "t1='a\u1234Xc', t2='A\u1234_C'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.73a "t1='abcde', t2='a%e'" \
"t1 LIKE t2 ESCAPE '\u1234'" 1
test_expr expr-5.73b "t1='abcde', t2='A%E'" \
"t1 LIKE t2 ESCAPE '\u1234'" $NCSL
test_expr expr-5.74a "t1='abcde', t2='a\u1234%e'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.74b "t1='abcde', t2='A\u1234%E'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.75a "t1='a\u1234cde', t2='a\u1234%e'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.75b "t1='a\u1234cde', t2='A\u1234%E'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.76a "t1='a\u1234cde', t2='a\u1234\u1234%e'" \
"t1 LIKE t2 ESCAPE '\u1234'" 1
test_expr expr-5.76b "t1='a\u1234cde', t2='A\u1234\u1234%E'" \
"t1 LIKE t2 ESCAPE '\u1234'" $NCSL
test_expr expr-5.77a "t1='abc\u1234', t2='a%\u1234\u1234'" \
"t1 LIKE t2 ESCAPE '\u1234'" 1
test_expr expr-5.77b "t1='abc\u1234', t2='A%\u1234\u1234'" \
"t1 LIKE t2 ESCAPE '\u1234'" $NCSL
test_expr expr-5.78a "t1='abc_', t2='a%\u1234_'" \
"t1 LIKE t2 ESCAPE '\u1234'" 1
test_expr expr-5.78b "t1='abc_', t2='A%\u1234_'" \
"t1 LIKE t2 ESCAPE '\u1234'" $NCSL
test_expr expr-5.79a "t1='abc\u1234', t2='a%\u1234_'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
test_expr expr-5.79b "t1='abc\u1234', t2='A%\u1234_'" \
"t1 LIKE t2 ESCAPE '\u1234'" 0
}
test_expr expr-6.1 {t1='abc', t2='xyz'} {t1 GLOB t2} 0
test_expr expr-6.2 {t1='abc', t2='ABC'} {t1 GLOB t2} 0
test_expr expr-6.3 {t1='abc', t2='A?C'} {t1 GLOB t2} 0
test_expr expr-6.4 {t1='abc', t2='a?c'} {t1 GLOB t2} 1
test_expr expr-6.5 {t1='abc', t2='abc?'} {t1 GLOB t2} 0
test_expr expr-6.6 {t1='abc', t2='A*C'} {t1 GLOB t2} 0
test_expr expr-6.7 {t1='abc', t2='a*c'} {t1 GLOB t2} 1
test_expr expr-6.8 {t1='abxyzzyc', t2='a*c'} {t1 GLOB t2} 1
test_expr expr-6.9 {t1='abxyzzy', t2='a*c'} {t1 GLOB t2} 0
test_expr expr-6.10 {t1='abxyzzycx', t2='a*c'} {t1 GLOB t2} 0
test_expr expr-6.11 {t1='abc', t2='xyz'} {t1 NOT GLOB t2} 1
test_expr expr-6.12 {t1='abc', t2='abc'} {t1 NOT GLOB t2} 0
test_expr expr-6.13 {t1='abc', t2='a[bx]c'} {t1 GLOB t2} 1
test_expr expr-6.14 {t1='abc', t2='a[cx]c'} {t1 GLOB t2} 0
test_expr expr-6.15 {t1='abc', t2='a[a-d]c'} {t1 GLOB t2} 1
test_expr expr-6.16 {t1='abc', t2='a[^a-d]c'} {t1 GLOB t2} 0
test_expr expr-6.17 {t1='abc', t2='a[A-Dc]c'} {t1 GLOB t2} 0
test_expr expr-6.18 {t1='abc', t2='a[^A-Dc]c'} {t1 GLOB t2} 1
test_expr expr-6.19 {t1='abc', t2='a[]b]c'} {t1 GLOB t2} 1
test_expr expr-6.20 {t1='abc', t2='a[^]b]c'} {t1 GLOB t2} 0
test_expr expr-6.21a {t1='abcdefg', t2='a*[de]g'} {t1 GLOB t2} 0
test_expr expr-6.21b {t1='abcdefg', t2='a*[df]g'} {t1 GLOB t2} 1
test_expr expr-6.21c {t1='abcdefg', t2='a*[d-h]g'} {t1 GLOB t2} 1
test_expr expr-6.21d {t1='abcdefg', t2='a*[b-e]g'} {t1 GLOB t2} 0
test_expr expr-6.22a {t1='abcdefg', t2='a*[^de]g'} {t1 GLOB t2} 1
test_expr expr-6.22b {t1='abcdefg', t2='a*[^def]g'} {t1 GLOB t2} 0
test_expr expr-6.23 {t1='abcdefg', t2='a*?g'} {t1 GLOB t2} 1
test_expr expr-6.24 {t1='ac', t2='a*c'} {t1 GLOB t2} 1
test_expr expr-6.25 {t1='ac', t2='a*?c'} {t1 GLOB t2} 0
test_expr expr-6.26 {t1='a*c', t2='a[*]c'} {t1 GLOB t2} 1
test_expr expr-6.27 {t1='a?c', t2='a[?]c'} {t1 GLOB t2} 1
test_expr expr-6.28 {t1='a[c', t2='a[[]c'} {t1 GLOB t2} 1
# These tests only work on versions of TCL that support Unicode
#
if {"\u1234"!="u1234"} {
test_expr expr-6.26 "t1='a\u0080c', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.27 "t1='a\u07ffc', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.28 "t1='a\u0800c', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.29 "t1='a\uffffc', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.30 "t1='a\u1234', t2='a?'" {t1 GLOB t2} 1
test_expr expr-6.31 "t1='a\u1234', t2='a??'" {t1 GLOB t2} 0
test_expr expr-6.32 "t1='ax\u1234', t2='a?\u1234'" {t1 GLOB t2} 1
test_expr expr-6.33 "t1='ax\u1234', t2='a*\u1234'" {t1 GLOB t2} 1
test_expr expr-6.34 "t1='ax\u1234y\u1234', t2='a*\u1234'" {t1 GLOB t2} 1
test_expr expr-6.35 "t1='a\u1234b', t2='a\[x\u1234y\]b'" {t1 GLOB t2} 1
test_expr expr-6.36 "t1='a\u1234b', t2='a\[\u1233-\u1235\]b'" {t1 GLOB t2} 1
test_expr expr-6.37 "t1='a\u1234b', t2='a\[\u1234-\u124f\]b'" {t1 GLOB t2} 1
test_expr expr-6.38 "t1='a\u1234b', t2='a\[\u1235-\u124f\]b'" {t1 GLOB t2} 0
test_expr expr-6.39 "t1='a\u1234b', t2='a\[a-\u1235\]b'" {t1 GLOB t2} 1
test_expr expr-6.40 "t1='a\u1234b', t2='a\[a-\u1234\]b'" {t1 GLOB t2} 1
test_expr expr-6.41 "t1='a\u1234b', t2='a\[a-\u1233\]b'" {t1 GLOB t2} 0
}
test_expr expr-6.51 {t1='ABC', t2='xyz'} {t1 GLOB t2} 0
test_expr expr-6.52 {t1='ABC', t2='abc'} {t1 GLOB t2} 0
test_expr expr-6.53 {t1='ABC', t2='a?c'} {t1 GLOB t2} 0
test_expr expr-6.54 {t1='ABC', t2='A?C'} {t1 GLOB t2} 1
test_expr expr-6.55 {t1='ABC', t2='abc?'} {t1 GLOB t2} 0
test_expr expr-6.56 {t1='ABC', t2='a*c'} {t1 GLOB t2} 0
test_expr expr-6.57 {t1='ABC', t2='A*C'} {t1 GLOB t2} 1
test_expr expr-6.58 {t1='ABxyzzyC', t2='A*C'} {t1 GLOB t2} 1
test_expr expr-6.59 {t1='ABxyzzy', t2='A*C'} {t1 GLOB t2} 0
test_expr expr-6.60 {t1='ABxyzzyCx', t2='A*C'} {t1 GLOB t2} 0
test_expr expr-6.61 {t1='ABC', t2='xyz'} {t1 NOT GLOB t2} 1
test_expr expr-6.62 {t1='ABC', t2='ABC'} {t1 NOT GLOB t2} 0
test_expr expr-6.63 {t1='ABC', t2='A[Bx]C'} {t1 GLOB t2} 1
test_expr expr-6.64 {t1='ABC', t2='A[Cx]C'} {t1 GLOB t2} 0
test_expr expr-6.65 {t1='ABC', t2='A[A-D]C'} {t1 GLOB t2} 1
test_expr expr-6.66 {t1='ABC', t2='A[^A-D]C'} {t1 GLOB t2} 0
test_expr expr-6.67 {t1='ABC', t2='A[a-dC]C'} {t1 GLOB t2} 0
test_expr expr-6.68 {t1='ABC', t2='A[^a-dC]C'} {t1 GLOB t2} 1
test_expr expr-6.69a {t1='ABC', t2='A[]B]C'} {t1 GLOB t2} 1
test_expr expr-6.69b {t1='A]C', t2='A[]B]C'} {t1 GLOB t2} 1
test_expr expr-6.70a {t1='ABC', t2='A[^]B]C'} {t1 GLOB t2} 0
test_expr expr-6.70b {t1='AxC', t2='A[^]B]C'} {t1 GLOB t2} 1
test_expr expr-6.70c {t1='A]C', t2='A[^]B]C'} {t1 GLOB t2} 0
test_expr expr-6.71 {t1='ABCDEFG', t2='A*[DE]G'} {t1 GLOB t2} 0
test_expr expr-6.72 {t1='ABCDEFG', t2='A*[^DE]G'} {t1 GLOB t2} 1
test_expr expr-6.73 {t1='ABCDEFG', t2='A*?G'} {t1 GLOB t2} 1
test_expr expr-6.74 {t1='AC', t2='A*C'} {t1 GLOB t2} 1
test_expr expr-6.75 {t1='AC', t2='A*?C'} {t1 GLOB t2} 0
test_expr expr-6.63 {t1=NULL, t2='a*?c'} {t1 GLOB t2} {{}}
test_expr expr-6.64 {t1='ac', t2=NULL} {t1 GLOB t2} {{}}
test_expr expr-6.65 {t1=NULL, t2='a*?c'} {t1 NOT GLOB t2} {{}}
test_expr expr-6.66 {t1='ac', t2=NULL} {t1 NOT GLOB t2} {{}}
# Check that the affinity of a CAST expression is calculated correctly.
ifcapable cast {
test_expr expr-6.67 {t1='01', t2=1} {t1 = t2} 0
test_expr expr-6.68 {t1='1', t2=1} {t1 = t2} 1
test_expr expr-6.69 {t1='01', t2=1} {CAST(t1 AS INTEGER) = t2} 1
}
test_expr expr-case.1 {i1=1, i2=2} \
{CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} ne
test_expr expr-case.2 {i1=2, i2=2} \
{CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} eq
test_expr expr-case.3 {i1=NULL, i2=2} \
{CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} ne
test_expr expr-case.4 {i1=2, i2=NULL} \
{CASE WHEN i1 = i2 THEN 'eq' ELSE 'ne' END} ne
test_expr expr-case.5 {i1=2} \
{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'error' END} two
test_expr expr-case.6 {i1=1} \
{CASE i1 WHEN 1 THEN 'one' WHEN NULL THEN 'two' ELSE 'error' END} one
test_expr expr-case.7 {i1=2} \
{CASE i1 WHEN 1 THEN 'one' WHEN NULL THEN 'two' ELSE 'error' END} error
test_expr expr-case.8 {i1=3} \
{CASE i1 WHEN 1 THEN 'one' WHEN NULL THEN 'two' ELSE 'error' END} error
test_expr expr-case.9 {i1=3} \
{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'error' END} error
test_expr expr-case.10 {i1=3} \
{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' END} {{}}
test_expr expr-case.11 {i1=null} \
{CASE i1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 3 END} 3
test_expr expr-case.12 {i1=1} \
{CASE i1 WHEN 1 THEN null WHEN 2 THEN 'two' ELSE 3 END} {{}}
test_expr expr-case.13 {i1=7} \
{ CASE WHEN i1 < 5 THEN 'low'
WHEN i1 < 10 THEN 'medium'
WHEN i1 < 15 THEN 'high' ELSE 'error' END} medium
# The sqliteExprIfFalse and sqliteExprIfTrue routines are only
# executed as part of a WHERE clause. Create a table suitable
# for testing these functions.
#
execsql {DROP TABLE test1}
execsql {CREATE TABLE test1(a int, b int);}
for {set i 1} {$i<=20} {incr i} {
execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
}
execsql "INSERT INTO test1 VALUES(NULL,0)"
do_test expr-7.1 {
execsql {SELECT * FROM test1 ORDER BY a}
} {{} 0 1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024 11 2048 12 4096 13 8192 14 16384 15 32768 16 65536 17 131072 18 262144 19 524288 20 1048576}
proc test_expr2 {name expr result} {
do_test $name [format {
execsql {SELECT a FROM test1 WHERE %s ORDER BY a}
} $expr] $result
}
test_expr2 expr-7.2 {a<10 AND a>8} {9}
test_expr2 expr-7.3 {a<=10 AND a>=8} {8 9 10}
test_expr2 expr-7.4 {a>=8 AND a<=10} {8 9 10}
test_expr2 expr-7.5 {a>=20 OR a<=1} {1 20}
test_expr2 expr-7.6 {b!=4 AND a<=3} {1 3}
test_expr2 expr-7.7 {b==8 OR b==16 OR b==32} {3 4 5}
test_expr2 expr-7.8 {NOT b<>8 OR b==1024} {3 10}
test_expr2 expr-7.9 {b LIKE '10%'} {10 20}
test_expr2 expr-7.10 {b LIKE '_4'} {6}
test_expr2 expr-7.11 {a GLOB '1?'} {10 11 12 13 14 15 16 17 18 19}
test_expr2 expr-7.12 {b GLOB '1*4'} {10 14}
test_expr2 expr-7.13 {b GLOB '*1[456]'} {4}
test_expr2 expr-7.14 {a ISNULL} {{}}
test_expr2 expr-7.15 {a NOTNULL AND a<3} {1 2}
test_expr2 expr-7.16 {a AND a<3} {1 2}
test_expr2 expr-7.17 {NOT a} {}
test_expr2 expr-7.18 {a==11 OR (b>1000 AND b<2000)} {10 11}
test_expr2 expr-7.19 {a<=1 OR a>=20} {1 20}
test_expr2 expr-7.20 {a<1 OR a>20} {}
test_expr2 expr-7.21 {a>19 OR a<1} {20}
test_expr2 expr-7.22 {a!=1 OR a=100} \
{2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20}
test_expr2 expr-7.23 {(a notnull AND a<4) OR a==8} {1 2 3 8}
test_expr2 expr-7.24 {a LIKE '2_' OR a==8} {8 20}
test_expr2 expr-7.25 {a GLOB '2?' OR a==8} {8 20}
test_expr2 expr-7.26 {a isnull OR a=8} {{} 8}
test_expr2 expr-7.27 {a notnull OR a=8} \
{1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20}
test_expr2 expr-7.28 {a<0 OR b=0} {{}}
test_expr2 expr-7.29 {b=0 OR a<0} {{}}
test_expr2 expr-7.30 {a<0 AND b=0} {}
test_expr2 expr-7.31 {b=0 AND a<0} {}
test_expr2 expr-7.32 {a IS NULL AND (a<0 OR b=0)} {{}}
test_expr2 expr-7.33 {a IS NULL AND (b=0 OR a<0)} {{}}
test_expr2 expr-7.34 {a IS NULL AND (a<0 AND b=0)} {}
test_expr2 expr-7.35 {a IS NULL AND (b=0 AND a<0)} {}
test_expr2 expr-7.32 {(a<0 OR b=0) AND a IS NULL} {{}}
test_expr2 expr-7.33 {(b=0 OR a<0) AND a IS NULL} {{}}
test_expr2 expr-7.34 {(a<0 AND b=0) AND a IS NULL} {}
test_expr2 expr-7.35 {(b=0 AND a<0) AND a IS NULL} {}
test_expr2 expr-7.36 {a<2 OR (a<0 OR b=0)} {{} 1}
test_expr2 expr-7.37 {a<2 OR (b=0 OR a<0)} {{} 1}
test_expr2 expr-7.38 {a<2 OR (a<0 AND b=0)} {1}
test_expr2 expr-7.39 {a<2 OR (b=0 AND a<0)} {1}
test_expr2 expr-7.40 {((a<2 OR a IS NULL) AND b<3) OR b>1e10} {{} 1}
test_expr2 expr-7.41 {a BETWEEN -1 AND 1} {1}
test_expr2 expr-7.42 {a NOT BETWEEN 2 AND 100} {1}
test_expr2 expr-7.43 {(b+1234)||'this is a string that is at least 32 characters long' BETWEEN 1 AND 2} {}
test_expr2 expr-7.44 {123||'xabcdefghijklmnopqrstuvwyxz01234567890'||a BETWEEN '123a' AND '123b'} {}
test_expr2 expr-7.45 {((123||'xabcdefghijklmnopqrstuvwyxz01234567890'||a) BETWEEN '123a' AND '123b')<0} {}
test_expr2 expr-7.46 {((123||'xabcdefghijklmnopqrstuvwyxz01234567890'||a) BETWEEN '123a' AND '123z')>0} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20}
test_expr2 expr-7.50 {((a between 1 and 2 OR 0) AND 1) OR 0} {1 2}
test_expr2 expr-7.51 {((a not between 3 and 100 OR 0) AND 1) OR 0} {1 2}
ifcapable subquery {
test_expr2 expr-7.52 {((a in (1,2) OR 0) AND 1) OR 0} {1 2}
test_expr2 expr-7.53 \
{((a not in (3,4,5,6,7,8,9,10) OR 0) AND a<11) OR 0} {1 2}
}
test_expr2 expr-7.54 {((a>0 OR 0) AND a<3) OR 0} {1 2}
ifcapable subquery {
test_expr2 expr-7.55 {((a in (1,2) OR 0) IS NULL AND 1) OR 0} {{}}
test_expr2 expr-7.56 \
{((a not in (3,4,5,6,7,8,9,10) IS NULL OR 0) AND 1) OR 0} {{}}
}
test_expr2 expr-7.57 {((a>0 IS NULL OR 0) AND 1) OR 0} {{}}
test_expr2 expr-7.58 {(a||'')<='1'} {1}
test_expr2 expr-7.59 {LIKE('10%',b)} {10 20}
test_expr2 expr-7.60 {LIKE('_4',b)} {6}
test_expr2 expr-7.61 {GLOB('1?',a)} {10 11 12 13 14 15 16 17 18 19}
test_expr2 expr-7.62 {GLOB('1*4',b)} {10 14}
test_expr2 expr-7.63 {GLOB('*1[456]',b)} {4}
# Test the CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP expressions.
#
set sqlite_current_time 1157124849
do_test expr-8.1 {
execsql {SELECT CURRENT_TIME}
} {15:34:09}
do_test expr-8.2 {
execsql {SELECT CURRENT_DATE}
} {2006-09-01}
do_test expr-8.3 {
execsql {SELECT CURRENT_TIMESTAMP}
} {{2006-09-01 15:34:09}}
ifcapable datetime {
do_test expr-8.4 {
execsql {SELECT CURRENT_TIME==time('now');}
} 1
do_test expr-8.5 {
execsql {SELECT CURRENT_DATE==date('now');}
} 1
do_test expr-8.6 {
execsql {SELECT CURRENT_TIMESTAMP==datetime('now');}
} 1
}
set sqlite_current_time 0
do_test expr-9.1 {
execsql {SELECT round(-('-'||'123'))}
} 123.0
# Test an error message that can be generated by the LIKE expression
do_test expr-10.1 {
catchsql {SELECT 'abc' LIKE 'abc' ESCAPE ''}
} {1 {ESCAPE expression must be a single character}}
do_test expr-10.2 {
catchsql {SELECT 'abc' LIKE 'abc' ESCAPE 'ab'}
} {1 {ESCAPE expression must be a single character}}
# If we specify an integer constant that is bigger than the largest
# possible integer, code the integer as a real number.
#
do_test expr-11.1 {
execsql {SELECT typeof(9223372036854775807)}
} {integer}
do_test expr-11.2 {
execsql {SELECT typeof(9223372036854775808)}
} {real}
# These two statements used to leak memory (because of missing %destructor
# directives in parse.y).
do_test expr-12.1 {
catchsql {
SELECT (CASE a>4 THEN 1 ELSE 0 END) FROM test1;
}
} {1 {near "THEN": syntax error}}
do_test expr-12.2 {
catchsql {
SELECT (CASE WHEN a>4 THEN 1 ELSE 0) FROM test1;
}
} {1 {near ")": syntax error}}
finish_test
+77
View File
@@ -0,0 +1,77 @@
# 2001 September 15
#
# 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 regression tests for SQLite library.
#
# This file implements tests for foreign keys.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!foreignkey} {
finish_test
return
}
# Create a table and some data to work with.
#
do_test fkey1-1.0 {
execsql {
CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b INTEGER
REFERENCES t1 ON DELETE CASCADE
REFERENCES t2,
c TEXT,
FOREIGN KEY (b,c) REFERENCES t2(x,y) ON UPDATE CASCADE
);
}
} {}
do_test fkey1-1.1 {
execsql {
CREATE TABLE t2(
x INTEGER PRIMARY KEY,
y TEXT
);
}
} {}
do_test fkey1-1.2 {
execsql {
CREATE TABLE t3(
a INTEGER REFERENCES t2,
b INTEGER REFERENCES t1,
FOREIGN KEY (a,b) REFERENCES t2(x,y)
);
}
} {}
do_test fkey1-2.1 {
execsql {
CREATE TABLE t4(a integer primary key);
CREATE TABLE t5(x references t4);
CREATE TABLE t6(x references t4);
CREATE TABLE t7(x references t4);
CREATE TABLE t8(x references t4);
CREATE TABLE t9(x references t4);
CREATE TABLE t10(x references t4);
DROP TABLE t7;
DROP TABLE t9;
DROP TABLE t5;
DROP TABLE t8;
DROP TABLE t6;
DROP TABLE t10;
}
} {}
finish_test
+60
View File
@@ -0,0 +1,60 @@
# 2005 December 29
#
# 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 regression tests for SQLite library.
#
# This file implements tests to verify that the new serial_type
# values of 8 (integer 0) and 9 (integer 1) work correctly.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
db eval {PRAGMA legacy_file_format=OFF}
# The size of the database depends on whether or not autovacuum
# is enabled.
#
if {[db one {PRAGMA auto_vacuum}]} {
set small 3072
set large 5120
} else {
set small 2048
set large 4096
}
do_test format4-1.1 {
execsql {
CREATE TABLE t1(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
INSERT INTO t1 VALUES(0,0,0,0,0,0,0,0,0,0);
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM t1;
}
file size test.db
} $small
do_test format4-1.2 {
execsql {
UPDATE t1 SET x0=1, x1=1, x2=1, x3=1, x4=1, x5=1, x6=1, x7=1, x8=1, x9=1
}
file size test.db
} $small
do_test format4-1.3 {
execsql {
UPDATE t1 SET x0=2, x1=2, x2=2, x3=2, x4=2, x5=2, x6=2, x7=2, x8=2, x9=2
}
file size test.db
} $large
finish_test
+186
View File
@@ -0,0 +1,186 @@
# 2006 September 9
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the FTS1 module.
#
# $Id: fts1a.test,v 1.4 2006/09/28 19:43:32 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS1 is defined, omit this file.
ifcapable !fts1 {
finish_test
return
}
# Construct a full-text search table containing five keywords:
# one, two, three, four, and five, in various combinations. The
# rowid for each will be a bitmask for the elements it contains.
#
db eval {
CREATE VIRTUAL TABLE t1 USING fts1(content);
INSERT INTO t1(content) VALUES('one');
INSERT INTO t1(content) VALUES('two');
INSERT INTO t1(content) VALUES('one two');
INSERT INTO t1(content) VALUES('three');
INSERT INTO t1(content) VALUES('one three');
INSERT INTO t1(content) VALUES('two three');
INSERT INTO t1(content) VALUES('one two three');
INSERT INTO t1(content) VALUES('four');
INSERT INTO t1(content) VALUES('one four');
INSERT INTO t1(content) VALUES('two four');
INSERT INTO t1(content) VALUES('one two four');
INSERT INTO t1(content) VALUES('three four');
INSERT INTO t1(content) VALUES('one three four');
INSERT INTO t1(content) VALUES('two three four');
INSERT INTO t1(content) VALUES('one two three four');
INSERT INTO t1(content) VALUES('five');
INSERT INTO t1(content) VALUES('one five');
INSERT INTO t1(content) VALUES('two five');
INSERT INTO t1(content) VALUES('one two five');
INSERT INTO t1(content) VALUES('three five');
INSERT INTO t1(content) VALUES('one three five');
INSERT INTO t1(content) VALUES('two three five');
INSERT INTO t1(content) VALUES('one two three five');
INSERT INTO t1(content) VALUES('four five');
INSERT INTO t1(content) VALUES('one four five');
INSERT INTO t1(content) VALUES('two four five');
INSERT INTO t1(content) VALUES('one two four five');
INSERT INTO t1(content) VALUES('three four five');
INSERT INTO t1(content) VALUES('one three four five');
INSERT INTO t1(content) VALUES('two three four five');
INSERT INTO t1(content) VALUES('one two three four five');
}
do_test fts1a-1.1 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one'}
} {1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31}
do_test fts1a-1.2 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one two'}
} {3 7 11 15 19 23 27 31}
do_test fts1a-1.3 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'two one'}
} {3 7 11 15 19 23 27 31}
do_test fts1a-1.4 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one two three'}
} {7 15 23 31}
do_test fts1a-1.5 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one three two'}
} {7 15 23 31}
do_test fts1a-1.6 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'two three one'}
} {7 15 23 31}
do_test fts1a-1.7 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'two one three'}
} {7 15 23 31}
do_test fts1a-1.8 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'three one two'}
} {7 15 23 31}
do_test fts1a-1.9 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'three two one'}
} {7 15 23 31}
do_test fts1a-1.10 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one two THREE'}
} {7 15 23 31}
do_test fts1a-1.11 {
execsql {SELECT rowid FROM t1 WHERE content MATCH ' ONE Two three '}
} {7 15 23 31}
do_test fts1a-2.1 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one"'}
} {1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31}
do_test fts1a-2.2 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one two"'}
} {3 7 11 15 19 23 27 31}
do_test fts1a-2.3 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"two one"'}
} {}
do_test fts1a-2.4 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one two three"'}
} {7 15 23 31}
do_test fts1a-2.5 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one three two"'}
} {}
do_test fts1a-2.6 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one two three four"'}
} {15 31}
do_test fts1a-2.7 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one three two four"'}
} {}
do_test fts1a-2.8 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one three five"'}
} {21}
do_test fts1a-2.9 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one three" five'}
} {21 29}
do_test fts1a-2.10 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'five "one three"'}
} {21 29}
do_test fts1a-2.11 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'five "one three" four'}
} {29}
do_test fts1a-2.12 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'five four "one three"'}
} {29}
do_test fts1a-2.13 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one three" four five'}
} {29}
do_test fts1a-3.1 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one'}
} {1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31}
do_test fts1a-3.2 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one -two'}
} {1 5 9 13 17 21 25 29}
do_test fts1a-3.3 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '-two one'}
} {1 5 9 13 17 21 25 29}
do_test fts1a-4.1 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one OR two'}
} {1 2 3 5 6 7 9 10 11 13 14 15 17 18 19 21 22 23 25 26 27 29 30 31}
do_test fts1a-4.2 {
execsql {SELECT rowid FROM t1 WHERE content MATCH '"one two" OR three'}
} {3 4 5 6 7 11 12 13 14 15 19 20 21 22 23 27 28 29 30 31}
do_test fts1a-4.3 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'three OR "one two"'}
} {3 4 5 6 7 11 12 13 14 15 19 20 21 22 23 27 28 29 30 31}
do_test fts1a-4.4 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one two OR three'}
} {3 5 7 11 13 15 19 21 23 27 29 31}
do_test fts1a-4.5 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'three OR two one'}
} {3 5 7 11 13 15 19 21 23 27 29 31}
do_test fts1a-4.6 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'one two OR three OR four'}
} {3 5 7 9 11 13 15 19 21 23 25 27 29 31}
do_test fts1a-4.7 {
execsql {SELECT rowid FROM t1 WHERE content MATCH 'two OR three OR four one'}
} {3 5 7 9 11 13 15 19 21 23 25 27 29 31}
# Test the ability to handle NULL content
#
do_test fts1a-5.1 {
execsql {INSERT INTO t1(content) VALUES(NULL)}
} {}
do_test fts1a-5.2 {
set rowid [db last_insert_rowid]
execsql {SELECT content FROM t1 WHERE rowid=$rowid}
} {{}}
do_test fts1a-5.3 {
execsql {SELECT rowid FROM t1 WHERE content MATCH NULL}
} {}
finish_test
+147
View File
@@ -0,0 +1,147 @@
# 2006 September 13
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the FTS1 module.
#
# $Id: fts1b.test,v 1.4 2006/09/18 02:12:48 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS1 is defined, omit this file.
ifcapable !fts1 {
finish_test
return
}
# Fill the full-text index "t1" with phrases in english, spanish,
# and german. For the i-th row, fill in the names for the bits
# that are set in the value of i. The least significant bit is
# 1. For example, the value 5 is 101 in binary which will be
# converted to "one three" in english.
#
proc fill_multilanguage_fulltext_t1 {} {
set english {one two three four five}
set spanish {un dos tres cuatro cinco}
set german {eine zwei drei vier funf}
for {set i 1} {$i<=31} {incr i} {
set cmd "INSERT INTO t1 VALUES"
set vset {}
foreach lang {english spanish german} {
set words {}
for {set j 0; set k 1} {$j<5} {incr j; incr k $k} {
if {$k&$i} {lappend words [lindex [set $lang] $j]}
}
lappend vset "'$words'"
}
set sql "INSERT INTO t1(english,spanish,german) VALUES([join $vset ,])"
# puts $sql
db eval $sql
}
}
# Construct a full-text search table containing five keywords:
# one, two, three, four, and five, in various combinations. The
# rowid for each will be a bitmask for the elements it contains.
#
db eval {
CREATE VIRTUAL TABLE t1 USING fts1(english,spanish,german);
}
fill_multilanguage_fulltext_t1
do_test fts1b-1.1 {
execsql {SELECT rowid FROM t1 WHERE english MATCH 'one'}
} {1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31}
do_test fts1b-1.2 {
execsql {SELECT rowid FROM t1 WHERE spanish MATCH 'one'}
} {}
do_test fts1b-1.3 {
execsql {SELECT rowid FROM t1 WHERE german MATCH 'one'}
} {}
do_test fts1b-1.4 {
execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'one'}
} {1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31}
do_test fts1b-1.5 {
execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'one dos drei'}
} {7 15 23 31}
do_test fts1b-1.6 {
execsql {SELECT english, spanish, german FROM t1 WHERE rowid=1}
} {one un eine}
do_test fts1b-1.7 {
execsql {SELECT rowid FROM t1 WHERE t1 MATCH '"one un"'}
} {}
do_test fts1b-2.1 {
execsql {
CREATE VIRTUAL TABLE t2 USING fts1(from,to);
INSERT INTO t2([from],[to]) VALUES ('one two three', 'four five six');
SELECT [from], [to] FROM t2
}
} {{one two three} {four five six}}
# Compute an SQL string that contains the words one, two, three,... to
# describe bits set in the value $i. Only the lower 5 bits are examined.
#
proc wordset {i} {
set x {}
for {set j 0; set k 1} {$j<5} {incr j; incr k $k} {
if {$k&$i} {lappend x [lindex {one two three four five} $j]}
}
return '$x'
}
# Create a new FTS table with three columns:
#
# norm: words for the bits of rowid
# plusone: words for the bits of rowid+1
# invert: words for the bits of ~rowid
#
db eval {
CREATE VIRTUAL TABLE t4 USING fts1([norm],'plusone',"invert");
}
for {set i 1} {$i<=15} {incr i} {
set vset [list [wordset $i] [wordset [expr {$i+1}]] [wordset [expr {~$i}]]]
db eval "INSERT INTO t4(norm,plusone,invert) VALUES([join $vset ,]);"
}
do_test fts1b-4.1 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one'}
} {1 3 5 7 9 11 13 15}
do_test fts1b-4.2 {
execsql {SELECT rowid FROM t4 WHERE norm MATCH 'one'}
} {1 3 5 7 9 11 13 15}
do_test fts1b-4.3 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'one'}
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15}
do_test fts1b-4.4 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'plusone:one'}
} {2 4 6 8 10 12 14}
do_test fts1b-4.5 {
execsql {SELECT rowid FROM t4 WHERE plusone MATCH 'one'}
} {2 4 6 8 10 12 14}
do_test fts1b-4.6 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one plusone:two'}
} {1 5 9 13}
do_test fts1b-4.7 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one two'}
} {1 3 5 7 9 11 13 15}
do_test fts1b-4.8 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'plusone:two norm:one'}
} {1 5 9 13}
do_test fts1b-4.9 {
execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'two norm:one'}
} {1 3 5 7 9 11 13 15}
finish_test
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
# 2006 October 1
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the FTS1 module, and in particular
# the Porter stemmer.
#
# $Id: fts1d.test,v 1.1 2006/10/01 18:41:21 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_ENABLE_FTS1 is defined, omit this file.
ifcapable !fts1 {
finish_test
return
}
do_test fts1d-1.1 {
execsql {
CREATE VIRTUAL TABLE t1 USING fts1(content, tokenize porter);
INSERT INTO t1(rowid, content) VALUES(1, 'running and jumping');
SELECT rowid FROM t1 WHERE content MATCH 'run jump';
}
} {1}
do_test fts1d-1.2 {
execsql {
SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'run jump';
}
} {{<b>running</b> and <b>jumping</b>}}
do_test fts1d-1.3 {
execsql {
INSERT INTO t1(rowid, content)
VALUES(2, 'abcdefghijklmnopqrstuvwyxz');
SELECT rowid, snippet(t1) FROM t1 WHERE t1 MATCH 'abcdefghijqrstuvwyxz'
}
} {2 <b>abcdefghijklmnopqrstuvwyxz</b>}
do_test fts1d-1.4 {
execsql {
SELECT rowid, snippet(t1) FROM t1 WHERE t1 MATCH 'abcdefghijXXXXqrstuvwyxz'
}
} {2 <b>abcdefghijklmnopqrstuvwyxz</b>}
do_test fts1d-1.5 {
execsql {
INSERT INTO t1(rowid, content)
VALUES(3, 'The value is 123456789');
SELECT rowid, snippet(t1) FROM t1 WHERE t1 MATCH '123789'
}
} {3 {The value is <b>123456789</b>}}
do_test fts1d-1.6 {
execsql {
SELECT rowid, snippet(t1) FROM t1 WHERE t1 MATCH '123000000789'
}
} {3 {The value is <b>123456789</b>}}
finish_test
File diff suppressed because it is too large Load Diff
+703
View File
@@ -0,0 +1,703 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.55 2006/09/16 21:45:14 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table to work with.
#
do_test func-0.0 {
execsql {CREATE TABLE tbl1(t1 text)}
foreach word {this program is free software} {
execsql "INSERT INTO tbl1 VALUES('$word')"
}
execsql {SELECT t1 FROM tbl1 ORDER BY t1}
} {free is program software this}
do_test func-0.1 {
execsql {
CREATE TABLE t2(a);
INSERT INTO t2 VALUES(1);
INSERT INTO t2 VALUES(NULL);
INSERT INTO t2 VALUES(345);
INSERT INTO t2 VALUES(NULL);
INSERT INTO t2 VALUES(67890);
SELECT * FROM t2;
}
} {1 {} 345 {} 67890}
# Check out the length() function
#
do_test func-1.0 {
execsql {SELECT length(t1) FROM tbl1 ORDER BY t1}
} {4 2 7 8 4}
do_test func-1.1 {
set r [catch {execsql {SELECT length(*) FROM tbl1 ORDER BY t1}} msg]
lappend r $msg
} {1 {wrong number of arguments to function length()}}
do_test func-1.2 {
set r [catch {execsql {SELECT length(t1,5) FROM tbl1 ORDER BY t1}} msg]
lappend r $msg
} {1 {wrong number of arguments to function length()}}
do_test func-1.3 {
execsql {SELECT length(t1), count(*) FROM tbl1 GROUP BY length(t1)
ORDER BY length(t1)}
} {2 1 4 2 7 1 8 1}
do_test func-1.4 {
execsql {SELECT coalesce(length(a),-1) FROM t2}
} {1 -1 3 -1 5}
# Check out the substr() function
#
do_test func-2.0 {
execsql {SELECT substr(t1,1,2) FROM tbl1 ORDER BY t1}
} {fr is pr so th}
do_test func-2.1 {
execsql {SELECT substr(t1,2,1) FROM tbl1 ORDER BY t1}
} {r s r o h}
do_test func-2.2 {
execsql {SELECT substr(t1,3,3) FROM tbl1 ORDER BY t1}
} {ee {} ogr ftw is}
do_test func-2.3 {
execsql {SELECT substr(t1,-1,1) FROM tbl1 ORDER BY t1}
} {e s m e s}
do_test func-2.4 {
execsql {SELECT substr(t1,-1,2) FROM tbl1 ORDER BY t1}
} {e s m e s}
do_test func-2.5 {
execsql {SELECT substr(t1,-2,1) FROM tbl1 ORDER BY t1}
} {e i a r i}
do_test func-2.6 {
execsql {SELECT substr(t1,-2,2) FROM tbl1 ORDER BY t1}
} {ee is am re is}
do_test func-2.7 {
execsql {SELECT substr(t1,-4,2) FROM tbl1 ORDER BY t1}
} {fr {} gr wa th}
do_test func-2.8 {
execsql {SELECT t1 FROM tbl1 ORDER BY substr(t1,2,20)}
} {this software free program is}
do_test func-2.9 {
execsql {SELECT substr(a,1,1) FROM t2}
} {1 {} 3 {} 6}
do_test func-2.10 {
execsql {SELECT substr(a,2,2) FROM t2}
} {{} {} 45 {} 78}
# Only do the following tests if TCL has UTF-8 capabilities
#
if {"\u1234"!="u1234"} {
# Put some UTF-8 characters in the database
#
do_test func-3.0 {
execsql {DELETE FROM tbl1}
foreach word "contains UTF-8 characters hi\u1234ho" {
execsql "INSERT INTO tbl1 VALUES('$word')"
}
execsql {SELECT t1 FROM tbl1 ORDER BY t1}
} "UTF-8 characters contains hi\u1234ho"
do_test func-3.1 {
execsql {SELECT length(t1) FROM tbl1 ORDER BY t1}
} {5 10 8 5}
do_test func-3.2 {
execsql {SELECT substr(t1,1,2) FROM tbl1 ORDER BY t1}
} {UT ch co hi}
do_test func-3.3 {
execsql {SELECT substr(t1,1,3) FROM tbl1 ORDER BY t1}
} "UTF cha con hi\u1234"
do_test func-3.4 {
execsql {SELECT substr(t1,2,2) FROM tbl1 ORDER BY t1}
} "TF ha on i\u1234"
do_test func-3.5 {
execsql {SELECT substr(t1,2,3) FROM tbl1 ORDER BY t1}
} "TF- har ont i\u1234h"
do_test func-3.6 {
execsql {SELECT substr(t1,3,2) FROM tbl1 ORDER BY t1}
} "F- ar nt \u1234h"
do_test func-3.7 {
execsql {SELECT substr(t1,4,2) FROM tbl1 ORDER BY t1}
} "-8 ra ta ho"
do_test func-3.8 {
execsql {SELECT substr(t1,-1,1) FROM tbl1 ORDER BY t1}
} "8 s s o"
do_test func-3.9 {
execsql {SELECT substr(t1,-3,2) FROM tbl1 ORDER BY t1}
} "F- er in \u1234h"
do_test func-3.10 {
execsql {SELECT substr(t1,-4,3) FROM tbl1 ORDER BY t1}
} "TF- ter ain i\u1234h"
do_test func-3.99 {
execsql {DELETE FROM tbl1}
foreach word {this program is free software} {
execsql "INSERT INTO tbl1 VALUES('$word')"
}
execsql {SELECT t1 FROM tbl1}
} {this program is free software}
} ;# End \u1234!=u1234
# Test the abs() and round() functions.
#
do_test func-4.1 {
execsql {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(2,1.2345678901234,-12345.67890);
INSERT INTO t1 VALUES(3,-2,-5);
}
catchsql {SELECT abs(a,b) FROM t1}
} {1 {wrong number of arguments to function abs()}}
do_test func-4.2 {
catchsql {SELECT abs() FROM t1}
} {1 {wrong number of arguments to function abs()}}
do_test func-4.3 {
catchsql {SELECT abs(b) FROM t1 ORDER BY a}
} {0 {2 1.2345678901234 2}}
do_test func-4.4 {
catchsql {SELECT abs(c) FROM t1 ORDER BY a}
} {0 {3 12345.6789 5}}
do_test func-4.4.1 {
execsql {SELECT abs(a) FROM t2}
} {1 {} 345 {} 67890}
do_test func-4.4.2 {
execsql {SELECT abs(t1) FROM tbl1}
} {0.0 0.0 0.0 0.0 0.0}
do_test func-4.5 {
catchsql {SELECT round(a,b,c) FROM t1}
} {1 {wrong number of arguments to function round()}}
do_test func-4.6 {
catchsql {SELECT round(b,2) FROM t1 ORDER BY b}
} {0 {-2.0 1.23 2.0}}
do_test func-4.7 {
catchsql {SELECT round(b,0) FROM t1 ORDER BY a}
} {0 {2.0 1.0 -2.0}}
do_test func-4.8 {
catchsql {SELECT round(c) FROM t1 ORDER BY a}
} {0 {3.0 -12346.0 -5.0}}
do_test func-4.9 {
catchsql {SELECT round(c,a) FROM t1 ORDER BY a}
} {0 {3.0 -12345.68 -5.0}}
do_test func-4.10 {
catchsql {SELECT 'x' || round(c,a) || 'y' FROM t1 ORDER BY a}
} {0 {x3.0y x-12345.68y x-5.0y}}
do_test func-4.11 {
catchsql {SELECT round() FROM t1 ORDER BY a}
} {1 {wrong number of arguments to function round()}}
do_test func-4.12 {
execsql {SELECT coalesce(round(a,2),'nil') FROM t2}
} {1.0 nil 345.0 nil 67890.0}
do_test func-4.13 {
execsql {SELECT round(t1,2) FROM tbl1}
} {0.0 0.0 0.0 0.0 0.0}
do_test func-4.14 {
execsql {SELECT typeof(round(5.1,1));}
} {real}
do_test func-4.15 {
execsql {SELECT typeof(round(5.1));}
} {real}
# Test the upper() and lower() functions
#
do_test func-5.1 {
execsql {SELECT upper(t1) FROM tbl1}
} {THIS PROGRAM IS FREE SOFTWARE}
do_test func-5.2 {
execsql {SELECT lower(upper(t1)) FROM tbl1}
} {this program is free software}
do_test func-5.3 {
execsql {SELECT upper(a), lower(a) FROM t2}
} {1 1 {} {} 345 345 {} {} 67890 67890}
do_test func-5.4 {
catchsql {SELECT upper(a,5) FROM t2}
} {1 {wrong number of arguments to function upper()}}
do_test func-5.5 {
catchsql {SELECT upper(*) FROM t2}
} {1 {wrong number of arguments to function upper()}}
# Test the coalesce() and nullif() functions
#
do_test func-6.1 {
execsql {SELECT coalesce(a,'xyz') FROM t2}
} {1 xyz 345 xyz 67890}
do_test func-6.2 {
execsql {SELECT coalesce(upper(a),'nil') FROM t2}
} {1 nil 345 nil 67890}
do_test func-6.3 {
execsql {SELECT coalesce(nullif(1,1),'nil')}
} {nil}
do_test func-6.4 {
execsql {SELECT coalesce(nullif(1,2),'nil')}
} {1}
do_test func-6.5 {
execsql {SELECT coalesce(nullif(1,NULL),'nil')}
} {1}
# Test the last_insert_rowid() function
#
do_test func-7.1 {
execsql {SELECT last_insert_rowid()}
} [db last_insert_rowid]
# Tests for aggregate functions and how they handle NULLs.
#
do_test func-8.1 {
ifcapable explain {
execsql {EXPLAIN SELECT sum(a) FROM t2;}
}
execsql {
SELECT sum(a), count(a), round(avg(a),2), min(a), max(a), count(*) FROM t2;
}
} {68236 3 22745.33 1 67890 5}
do_test func-8.2 {
execsql {
SELECT max('z+'||a||'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP') FROM t2;
}
} {z+67890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP}
ifcapable tempdb {
do_test func-8.3 {
execsql {
CREATE TEMP TABLE t3 AS SELECT a FROM t2 ORDER BY a DESC;
SELECT min('z+'||a||'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP') FROM t3;
}
} {z+1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP}
} else {
do_test func-8.3 {
execsql {
CREATE TABLE t3 AS SELECT a FROM t2 ORDER BY a DESC;
SELECT min('z+'||a||'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP') FROM t3;
}
} {z+1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP}
}
do_test func-8.4 {
execsql {
SELECT max('z+'||a||'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP') FROM t3;
}
} {z+67890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP}
# How do you test the random() function in a meaningful, deterministic way?
#
do_test func-9.1 {
execsql {
SELECT random() is not null;
}
} {1}
# Use the "sqlite_register_test_function" TCL command which is part of
# the text fixture in order to verify correct operation of some of
# the user-defined SQL function APIs that are not used by the built-in
# functions.
#
set ::DB [sqlite3_connection_pointer db]
sqlite_register_test_function $::DB testfunc
do_test func-10.1 {
catchsql {
SELECT testfunc(NULL,NULL);
}
} {1 {first argument should be one of: int int64 string double null value}}
do_test func-10.2 {
execsql {
SELECT testfunc(
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'int', 1234
);
}
} {1234}
do_test func-10.3 {
execsql {
SELECT testfunc(
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'string', NULL
);
}
} {{}}
do_test func-10.4 {
execsql {
SELECT testfunc(
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'double', 1.234
);
}
} {1.234}
do_test func-10.5 {
execsql {
SELECT testfunc(
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'int', 1234,
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'string', NULL,
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'double', 1.234,
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'int', 1234,
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'string', NULL,
'string', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'double', 1.234
);
}
} {1.234}
# Test the built-in sqlite_version(*) SQL function.
#
do_test func-11.1 {
execsql {
SELECT sqlite_version(*);
}
} [sqlite3 -version]
# Test that destructors passed to sqlite3 by calls to sqlite3_result_text()
# etc. are called. These tests use two special user-defined functions
# (implemented in func.c) only available in test builds.
#
# Function test_destructor() takes one argument and returns a copy of the
# text form of that argument. A destructor is associated with the return
# value. Function test_destructor_count() returns the number of outstanding
# destructor calls for values returned by test_destructor().
#
do_test func-12.1 {
execsql {
SELECT test_destructor('hello world'), test_destructor_count();
}
} {{hello world} 1}
do_test func-12.2 {
execsql {
SELECT test_destructor_count();
}
} {0}
do_test func-12.3 {
execsql {
SELECT test_destructor('hello')||' world', test_destructor_count();
}
} {{hello world} 0}
do_test func-12.4 {
execsql {
SELECT test_destructor_count();
}
} {0}
do_test func-12.5 {
execsql {
CREATE TABLE t4(x);
INSERT INTO t4 VALUES(test_destructor('hello'));
INSERT INTO t4 VALUES(test_destructor('world'));
SELECT min(test_destructor(x)), max(test_destructor(x)) FROM t4;
}
} {hello world}
do_test func-12.6 {
execsql {
SELECT test_destructor_count();
}
} {0}
do_test func-12.7 {
execsql {
DROP TABLE t4;
}
} {}
# Test that the auxdata API for scalar functions works. This test uses
# a special user-defined function only available in test builds,
# test_auxdata(). Function test_auxdata() takes any number of arguments.
btree_breakpoint
do_test func-13.1 {
execsql {
SELECT test_auxdata('hello world');
}
} {0}
do_test func-13.2 {
execsql {
CREATE TABLE t4(a, b);
INSERT INTO t4 VALUES('abc', 'def');
INSERT INTO t4 VALUES('ghi', 'jkl');
}
} {}
do_test func-13.3 {
execsql {
SELECT test_auxdata('hello world') FROM t4;
}
} {0 1}
do_test func-13.4 {
execsql {
SELECT test_auxdata('hello world', 123) FROM t4;
}
} {{0 0} {1 1}}
do_test func-13.5 {
execsql {
SELECT test_auxdata('hello world', a) FROM t4;
}
} {{0 0} {1 0}}
do_test func-13.6 {
execsql {
SELECT test_auxdata('hello'||'world', a) FROM t4;
}
} {{0 0} {1 0}}
# Test that auxilary data is preserved between calls for SQL variables.
do_test func-13.7 {
set DB [sqlite3_connection_pointer db]
set sql "SELECT test_auxdata( ? , a ) FROM t4;"
set STMT [sqlite3_prepare $DB $sql -1 TAIL]
sqlite3_bind_text $STMT 1 hello -1
set res [list]
while { "SQLITE_ROW"==[sqlite3_step $STMT] } {
lappend res [sqlite3_column_text $STMT 0]
}
lappend res [sqlite3_finalize $STMT]
} {{0 0} {1 0} SQLITE_OK}
# Make sure that a function with a very long name is rejected
do_test func-14.1 {
catch {
db function [string repeat X 254] {return "hello"}
}
} {0}
do_test func-14.2 {
catch {
db function [string repeat X 256] {return "hello"}
}
} {1}
do_test func-15.1 {
catchsql {
select test_error(NULL);
}
} {1 {}}
# Test the quote function for BLOB and NULL values.
do_test func-16.1 {
execsql {
CREATE TABLE tbl2(a, b);
}
set STMT [sqlite3_prepare $::DB "INSERT INTO tbl2 VALUES(?, ?)" -1 TAIL]
sqlite3_bind_blob $::STMT 1 abc 3
sqlite3_step $::STMT
sqlite3_finalize $::STMT
execsql {
SELECT quote(a), quote(b) FROM tbl2;
}
} {X'616263' NULL}
# Correctly handle function error messages that include %. Ticket #1354
#
do_test func-17.1 {
proc testfunc1 args {error "Error %d with %s percents %p"}
db function testfunc1 ::testfunc1
catchsql {
SELECT testfunc1(1,2,3);
}
} {1 {Error %d with %s percents %p}}
# The SUM function should return integer results when all inputs are integer.
#
do_test func-18.1 {
execsql {
CREATE TABLE t5(x);
INSERT INTO t5 VALUES(1);
INSERT INTO t5 VALUES(-99);
INSERT INTO t5 VALUES(10000);
SELECT sum(x) FROM t5;
}
} {9902}
do_test func-18.2 {
execsql {
INSERT INTO t5 VALUES(0.0);
SELECT sum(x) FROM t5;
}
} {9902.0}
# The sum of nothing is NULL. But the sum of all NULLs is NULL.
#
# The TOTAL of nothing is 0.0.
#
do_test func-18.3 {
execsql {
DELETE FROM t5;
SELECT sum(x), total(x) FROM t5;
}
} {{} 0.0}
do_test func-18.4 {
execsql {
INSERT INTO t5 VALUES(NULL);
SELECT sum(x), total(x) FROM t5
}
} {{} 0.0}
do_test func-18.5 {
execsql {
INSERT INTO t5 VALUES(NULL);
SELECT sum(x), total(x) FROM t5
}
} {{} 0.0}
do_test func-18.6 {
execsql {
INSERT INTO t5 VALUES(123);
SELECT sum(x), total(x) FROM t5
}
} {123 123.0}
# Ticket #1664, #1669, #1670, #1674: An integer overflow on SUM causes
# an error. The non-standard TOTAL() function continues to give a helpful
# result.
#
do_test func-18.10 {
execsql {
CREATE TABLE t6(x INTEGER);
INSERT INTO t6 VALUES(1);
INSERT INTO t6 VALUES(1<<62);
SELECT sum(x) - ((1<<62)+1) from t6;
}
} 0
do_test func-18.11 {
execsql {
SELECT typeof(sum(x)) FROM t6
}
} integer
do_test func-18.12 {
catchsql {
INSERT INTO t6 VALUES(1<<62);
SELECT sum(x) - ((1<<62)*2.0+1) from t6;
}
} {1 {integer overflow}}
do_test func-18.13 {
execsql {
SELECT total(x) - ((1<<62)*2.0+1) FROM t6
}
} 0.0
do_test func-18.14 {
execsql {
SELECT sum(-9223372036854775805);
}
} -9223372036854775805
ifcapable compound&&subquery {
do_test func-18.15 {
catchsql {
SELECT sum(x) FROM
(SELECT 9223372036854775807 AS x UNION ALL
SELECT 10 AS x);
}
} {1 {integer overflow}}
do_test func-18.16 {
catchsql {
SELECT sum(x) FROM
(SELECT 9223372036854775807 AS x UNION ALL
SELECT -10 AS x);
}
} {0 9223372036854775797}
do_test func-18.17 {
catchsql {
SELECT sum(x) FROM
(SELECT -9223372036854775807 AS x UNION ALL
SELECT 10 AS x);
}
} {0 -9223372036854775797}
do_test func-18.18 {
catchsql {
SELECT sum(x) FROM
(SELECT -9223372036854775807 AS x UNION ALL
SELECT -10 AS x);
}
} {1 {integer overflow}}
do_test func-18.19 {
catchsql {
SELECT sum(x) FROM (SELECT 9 AS x UNION ALL SELECT -10 AS x);
}
} {0 -1}
do_test func-18.20 {
catchsql {
SELECT sum(x) FROM (SELECT -9 AS x UNION ALL SELECT 10 AS x);
}
} {0 1}
do_test func-18.21 {
catchsql {
SELECT sum(x) FROM (SELECT -10 AS x UNION ALL SELECT 9 AS x);
}
} {0 -1}
do_test func-18.22 {
catchsql {
SELECT sum(x) FROM (SELECT 10 AS x UNION ALL SELECT -9 AS x);
}
} {0 1}
} ;# ifcapable compound&&subquery
# Integer overflow on abs()
#
do_test func-18.31 {
catchsql {
SELECT abs(-9223372036854775807);
}
} {0 9223372036854775807}
do_test func-18.32 {
catchsql {
SELECT abs(-9223372036854775807-1);
}
} {1 {integer overflow}}
# The MATCH function exists but is only a stub and always throws an error.
#
do_test func-19.1 {
execsql {
SELECT match(a,b) FROM t1 WHERE 0;
}
} {}
do_test func-19.2 {
catchsql {
SELECT 'abc' MATCH 'xyz';
}
} {1 {unable to use function MATCH in the requested context}}
do_test func-19.3 {
catchsql {
SELECT 'abc' NOT MATCH 'xyz';
}
} {1 {unable to use function MATCH in the requested context}}
do_test func-19.4 {
catchsql {
SELECT match(1,2,3);
}
} {1 {wrong number of arguments to function match()}}
# Soundex tests.
#
if {![catch {db eval {SELECT soundex('hello')}}]} {
set i 0
foreach {name sdx} {
euler E460
EULER E460
Euler E460
ellery E460
gauss G200
ghosh G200
hilbert H416
Heilbronn H416
knuth K530
kant K530
Lloyd L300
LADD L300
Lukasiewicz L222
Lissajous L222
A A000
12345 ?000
} {
incr i
do_test func-20.$i {
execsql {SELECT soundex($name)}
} $sdx
}
}
finish_test
+297
View File
@@ -0,0 +1,297 @@
# 2004 Jan 14
#
# 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 regression tests for TCL interface to the
# SQLite library.
#
# The focus of the tests in this file is the following interface:
#
# sqlite_commit_hook (tests hook-1..hook-3 inclusive)
# sqlite_update_hook (tests hook-4-*)
# sqlite_rollback_hook (tests hook-5.*)
#
# $Id: hook.test,v 1.11 2006/01/17 09:35:02 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test hook-1.2 {
db commit_hook
} {}
do_test hook-3.1 {
set commit_cnt 0
proc commit_hook {} {
incr ::commit_cnt
return 0
}
db commit_hook ::commit_hook
db commit_hook
} {::commit_hook}
do_test hook-3.2 {
set commit_cnt
} {0}
do_test hook-3.3 {
execsql {
CREATE TABLE t2(a,b);
}
set commit_cnt
} {1}
do_test hook-3.4 {
execsql {
INSERT INTO t2 VALUES(1,2);
INSERT INTO t2 SELECT a+1, b+1 FROM t2;
INSERT INTO t2 SELECT a+2, b+2 FROM t2;
}
set commit_cnt
} {4}
do_test hook-3.5 {
set commit_cnt {}
proc commit_hook {} {
set ::commit_cnt [execsql {SELECT * FROM t2}]
return 0
}
execsql {
INSERT INTO t2 VALUES(5,6);
}
set commit_cnt
} {1 2 2 3 3 4 4 5 5 6}
do_test hook-3.6 {
set commit_cnt {}
proc commit_hook {} {
set ::commit_cnt [execsql {SELECT * FROM t2}]
return 1
}
catchsql {
INSERT INTO t2 VALUES(6,7);
}
} {1 {constraint failed}}
do_test hook-3.7 {
set ::commit_cnt
} {1 2 2 3 3 4 4 5 5 6 6 7}
do_test hook-3.8 {
execsql {SELECT * FROM t2}
} {1 2 2 3 3 4 4 5 5 6}
# Test turnning off the commit hook
#
do_test hook-3.9 {
db commit_hook {}
set ::commit_cnt {}
execsql {
INSERT INTO t2 VALUES(7,8);
}
set ::commit_cnt
} {}
#----------------------------------------------------------------------------
# Tests for the update-hook.
#
# 4.1.* - Very simple tests. Test that the update hook is invoked correctly
# for INSERT, DELETE and UPDATE statements, including DELETE
# statements with no WHERE clause.
# 4.2.* - Check that the update-hook is invoked for rows modified by trigger
# bodies. Also that the database name is correctly reported when
# an attached database is modified.
# 4.3.* - Do some sorting, grouping, compound queries, population and
# depopulation of indices, to make sure the update-hook is not
# invoked incorrectly.
#
# Simple tests
do_test hook-4.1.1 {
catchsql {
DROP TABLE t1;
}
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
}
db update_hook [list lappend ::update_hook]
} {}
do_test hook-4.1.2 {
execsql {
INSERT INTO t1 VALUES(4, 'four');
DELETE FROM t1 WHERE b = 'two';
UPDATE t1 SET b = '' WHERE a = 1 OR a = 3;
DELETE FROM t1 WHERE 1; -- Avoid the truncate optimization (for now)
}
set ::update_hook
} [list \
INSERT main t1 4 \
DELETE main t1 2 \
UPDATE main t1 1 \
UPDATE main t1 3 \
DELETE main t1 1 \
DELETE main t1 3 \
DELETE main t1 4 \
]
set ::update_hook {}
ifcapable trigger {
do_test hook-4.2.1 {
catchsql {
DROP TABLE t2;
}
execsql {
CREATE TABLE t2(c INTEGER PRIMARY KEY, d);
CREATE TRIGGER t1_trigger AFTER INSERT ON t1 BEGIN
INSERT INTO t2 VALUES(new.a, new.b);
UPDATE t2 SET d = d || ' via trigger' WHERE new.a = c;
DELETE FROM t2 WHERE new.a = c;
END;
}
} {}
do_test hook-4.2.2 {
execsql {
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
}
set ::update_hook
} [list \
INSERT main t1 1 \
INSERT main t2 1 \
UPDATE main t2 1 \
DELETE main t2 1 \
INSERT main t1 2 \
INSERT main t2 2 \
UPDATE main t2 2 \
DELETE main t2 2 \
]
} else {
execsql {
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
}
}
# Update-hook + ATTACH
set ::update_hook {}
do_test hook-4.2.3 {
file delete -force test2.db
execsql {
ATTACH 'test2.db' AS aux;
CREATE TABLE aux.t3(a INTEGER PRIMARY KEY, b);
INSERT INTO aux.t3 SELECT * FROM t1;
UPDATE t3 SET b = 'two or so' WHERE a = 2;
DELETE FROM t3 WHERE 1; -- Avoid the truncate optimization (for now)
}
set ::update_hook
} [list \
INSERT aux t3 1 \
INSERT aux t3 2 \
UPDATE aux t3 2 \
DELETE aux t3 1 \
DELETE aux t3 2 \
]
ifcapable trigger {
execsql {
DROP TRIGGER t1_trigger;
}
}
# Test that other vdbe operations involving btree structures do not
# incorrectly invoke the update-hook.
set ::update_hook {}
do_test hook-4.3.1 {
execsql {
CREATE INDEX t1_i ON t1(b);
INSERT INTO t1 VALUES(3, 'three');
UPDATE t1 SET b = '';
DELETE FROM t1 WHERE a > 1;
}
set ::update_hook
} [list \
INSERT main t1 3 \
UPDATE main t1 1 \
UPDATE main t1 2 \
UPDATE main t1 3 \
DELETE main t1 2 \
DELETE main t1 3 \
]
set ::update_hook {}
ifcapable compound {
do_test hook-4.3.2 {
execsql {
SELECT * FROM t1 UNION SELECT * FROM t3;
SELECT * FROM t1 UNION ALL SELECT * FROM t3;
SELECT * FROM t1 INTERSECT SELECT * FROM t3;
SELECT * FROM t1 EXCEPT SELECT * FROM t3;
SELECT * FROM t1 ORDER BY b;
SELECT * FROM t1 GROUP BY b;
}
set ::update_hook
} [list]
}
db update_hook {}
#
#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
# Test the rollback-hook. The rollback-hook is a bit more complicated than
# either the commit or update hooks because a rollback can happen
# explicitly (an sql ROLLBACK statement) or implicitly (a constraint or
# error condition).
#
# hook-5.1.* - Test explicit rollbacks.
# hook-5.2.* - Test implicit rollbacks caused by constraint failure.
#
# hook-5.3.* - Test implicit rollbacks caused by IO errors.
# hook-5.4.* - Test implicit rollbacks caused by malloc() failure.
# hook-5.5.* - Test hot-journal rollbacks. Or should the rollback hook
# not be called for these?
#
do_test hook-5.0 {
# Configure the rollback hook to increment global variable
# $::rollback_hook each time it is invoked.
set ::rollback_hook 0
db rollback_hook [list incr ::rollback_hook]
} {}
# Test explicit rollbacks. Not much can really go wrong here.
#
do_test hook-5.1.1 {
set ::rollback_hook 0
execsql {
BEGIN;
ROLLBACK;
}
set ::rollback_hook
} {1}
# Test implicit rollbacks caused by constraints.
#
do_test hook-5.2.1 {
set ::rollback_hook 0
catchsql {
DROP TABLE t1;
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES('one', 'I');
INSERT INTO t1 VALUES('one', 'I');
}
set ::rollback_hook
} {1}
do_test hook-5.2.2 {
# Check that the INSERT transaction above really was rolled back.
execsql {
SELECT count(*) FROM t1;
}
} {1}
#
# End rollback-hook testing.
#----------------------------------------------------------------------------
finish_test
+367
View File
@@ -0,0 +1,367 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the IN and BETWEEN operator.
#
# $Id: in.test,v 1.17 2006/05/23 23:25:10 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Generate the test data we will need for the first squences of tests.
#
do_test in-1.0 {
execsql {
BEGIN;
CREATE TABLE t1(a int, b int);
}
for {set i 1} {$i<=10} {incr i} {
execsql "INSERT INTO t1 VALUES($i,[expr {int(pow(2,$i))}])"
}
execsql {
COMMIT;
SELECT count(*) FROM t1;
}
} {10}
# Do basic testing of BETWEEN.
#
do_test in-1.1 {
execsql {SELECT a FROM t1 WHERE b BETWEEN 10 AND 50 ORDER BY a}
} {4 5}
do_test in-1.2 {
execsql {SELECT a FROM t1 WHERE b NOT BETWEEN 10 AND 50 ORDER BY a}
} {1 2 3 6 7 8 9 10}
do_test in-1.3 {
execsql {SELECT a FROM t1 WHERE b BETWEEN a AND a*5 ORDER BY a}
} {1 2 3 4}
do_test in-1.4 {
execsql {SELECT a FROM t1 WHERE b NOT BETWEEN a AND a*5 ORDER BY a}
} {5 6 7 8 9 10}
do_test in-1.6 {
execsql {SELECT a FROM t1 WHERE b BETWEEN a AND a*5 OR b=512 ORDER BY a}
} {1 2 3 4 9}
do_test in-1.7 {
execsql {SELECT a+ 100*(a BETWEEN 1 and 3) FROM t1 ORDER BY b}
} {101 102 103 4 5 6 7 8 9 10}
# The rest of this file concentrates on testing the IN operator.
# Skip this if the library is compiled with SQLITE_OMIT_SUBQUERY
# (because the IN operator is unavailable).
#
ifcapable !subquery {
finish_test
return
}
# Testing of the IN operator using static lists on the right-hand side.
#
do_test in-2.1 {
execsql {SELECT a FROM t1 WHERE b IN (8,12,16,24,32) ORDER BY a}
} {3 4 5}
do_test in-2.2 {
execsql {SELECT a FROM t1 WHERE b NOT IN (8,12,16,24,32) ORDER BY a}
} {1 2 6 7 8 9 10}
do_test in-2.3 {
execsql {SELECT a FROM t1 WHERE b IN (8,12,16,24,32) OR b=512 ORDER BY a}
} {3 4 5 9}
do_test in-2.4 {
execsql {SELECT a FROM t1 WHERE b NOT IN (8,12,16,24,32) OR b=512 ORDER BY a}
} {1 2 6 7 8 9 10}
do_test in-2.5 {
execsql {SELECT a+100*(b IN (8,16,24)) FROM t1 ORDER BY b}
} {1 2 103 104 5 6 7 8 9 10}
do_test in-2.6 {
execsql {SELECT a FROM t1 WHERE b IN (b+8,64)}
} {6}
do_test in-2.7 {
execsql {SELECT a FROM t1 WHERE b IN (max(5,10,b),20)}
} {4 5 6 7 8 9 10}
do_test in-2.8 {
execsql {SELECT a FROM t1 WHERE b IN (8*2,64/2) ORDER BY b}
} {4 5}
do_test in-2.9 {
execsql {SELECT a FROM t1 WHERE b IN (max(5,10),20)}
} {}
do_test in-2.10 {
execsql {SELECT a FROM t1 WHERE min(0,b IN (a,30))}
} {}
do_test in-2.11 {
set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} msg]
lappend v $msg
} {1 {no such column: c}}
# Testing the IN operator where the right-hand side is a SELECT
#
do_test in-3.1 {
execsql {
SELECT a FROM t1
WHERE b IN (SELECT b FROM t1 WHERE a<5)
ORDER BY a
}
} {1 2 3 4}
do_test in-3.2 {
execsql {
SELECT a FROM t1
WHERE b IN (SELECT b FROM t1 WHERE a<5) OR b==512
ORDER BY a
}
} {1 2 3 4 9}
do_test in-3.3 {
execsql {
SELECT a + 100*(b IN (SELECT b FROM t1 WHERE a<5)) FROM t1 ORDER BY b
}
} {101 102 103 104 5 6 7 8 9 10}
# Make sure the UPDATE and DELETE commands work with IN-SELECT
#
do_test in-4.1 {
execsql {
UPDATE t1 SET b=b*2
WHERE b IN (SELECT b FROM t1 WHERE a>8)
}
execsql {SELECT b FROM t1 ORDER BY b}
} {2 4 8 16 32 64 128 256 1024 2048}
do_test in-4.2 {
execsql {
DELETE FROM t1 WHERE b IN (SELECT b FROM t1 WHERE a>8)
}
execsql {SELECT a FROM t1 ORDER BY a}
} {1 2 3 4 5 6 7 8}
do_test in-4.3 {
execsql {
DELETE FROM t1 WHERE b NOT IN (SELECT b FROM t1 WHERE a>4)
}
execsql {SELECT a FROM t1 ORDER BY a}
} {5 6 7 8}
# Do an IN with a constant RHS but where the RHS has many, many
# elements. We need to test that collisions in the hash table
# are resolved properly.
#
do_test in-5.1 {
execsql {
INSERT INTO t1 VALUES('hello', 'world');
SELECT * FROM t1
WHERE a IN (
'Do','an','IN','with','a','constant','RHS','but','where','the',
'has','many','elements','We','need','to','test','that',
'collisions','hash','table','are','resolved','properly',
'This','in-set','contains','thirty','one','entries','hello');
}
} {hello world}
# Make sure the IN operator works with INTEGER PRIMARY KEY fields.
#
do_test in-6.1 {
execsql {
CREATE TABLE ta(a INTEGER PRIMARY KEY, b);
INSERT INTO ta VALUES(1,1);
INSERT INTO ta VALUES(2,2);
INSERT INTO ta VALUES(3,3);
INSERT INTO ta VALUES(4,4);
INSERT INTO ta VALUES(6,6);
INSERT INTO ta VALUES(8,8);
INSERT INTO ta VALUES(10,
'This is a key that is long enough to require a malloc in the VDBE');
SELECT * FROM ta WHERE a<10;
}
} {1 1 2 2 3 3 4 4 6 6 8 8}
do_test in-6.2 {
execsql {
CREATE TABLE tb(a INTEGER PRIMARY KEY, b);
INSERT INTO tb VALUES(1,1);
INSERT INTO tb VALUES(2,2);
INSERT INTO tb VALUES(3,3);
INSERT INTO tb VALUES(5,5);
INSERT INTO tb VALUES(7,7);
INSERT INTO tb VALUES(9,9);
INSERT INTO tb VALUES(11,
'This is a key that is long enough to require a malloc in the VDBE');
SELECT * FROM tb WHERE a<10;
}
} {1 1 2 2 3 3 5 5 7 7 9 9}
do_test in-6.3 {
execsql {
SELECT a FROM ta WHERE b IN (SELECT a FROM tb);
}
} {1 2 3}
do_test in-6.4 {
execsql {
SELECT a FROM ta WHERE b NOT IN (SELECT a FROM tb);
}
} {4 6 8 10}
do_test in-6.5 {
execsql {
SELECT a FROM ta WHERE b IN (SELECT b FROM tb);
}
} {1 2 3 10}
do_test in-6.6 {
execsql {
SELECT a FROM ta WHERE b NOT IN (SELECT b FROM tb);
}
} {4 6 8}
do_test in-6.7 {
execsql {
SELECT a FROM ta WHERE a IN (SELECT a FROM tb);
}
} {1 2 3}
do_test in-6.8 {
execsql {
SELECT a FROM ta WHERE a NOT IN (SELECT a FROM tb);
}
} {4 6 8 10}
do_test in-6.9 {
execsql {
SELECT a FROM ta WHERE a IN (SELECT b FROM tb);
}
} {1 2 3}
do_test in-6.10 {
execsql {
SELECT a FROM ta WHERE a NOT IN (SELECT b FROM tb);
}
} {4 6 8 10}
# Tests of IN operator against empty sets. (Ticket #185)
#
do_test in-7.1 {
execsql {
SELECT a FROM t1 WHERE a IN ();
}
} {}
do_test in-7.2 {
execsql {
SELECT a FROM t1 WHERE a IN (5);
}
} {5}
do_test in-7.3 {
execsql {
SELECT a FROM t1 WHERE a NOT IN () ORDER BY a;
}
} {5 6 7 8 hello}
do_test in-7.4 {
execsql {
SELECT a FROM t1 WHERE a IN (5) AND b IN ();
}
} {}
do_test in-7.5 {
execsql {
SELECT a FROM t1 WHERE a IN (5) AND b NOT IN ();
}
} {5}
do_test in-7.6 {
execsql {
SELECT a FROM ta WHERE a IN ();
}
} {}
do_test in-7.7 {
execsql {
SELECT a FROM ta WHERE a NOT IN ();
}
} {1 2 3 4 6 8 10}
do_test in-8.1 {
execsql {
SELECT b FROM t1 WHERE a IN ('hello','there')
}
} {world}
do_test in-8.2 {
execsql {
SELECT b FROM t1 WHERE a IN ("hello",'there')
}
} {world}
# Test constructs of the form: expr IN tablename
#
do_test in-9.1 {
execsql {
CREATE TABLE t4 AS SELECT a FROM tb;
SELECT * FROM t4;
}
} {1 2 3 5 7 9 11}
do_test in-9.2 {
execsql {
SELECT b FROM t1 WHERE a IN t4;
}
} {32 128}
do_test in-9.3 {
execsql {
SELECT b FROM t1 WHERE a NOT IN t4;
}
} {64 256 world}
do_test in-9.4 {
catchsql {
SELECT b FROM t1 WHERE a NOT IN tb;
}
} {1 {only a single result allowed for a SELECT that is part of an expression}}
# IN clauses in CHECK constraints. Ticket #1645
#
do_test in-10.1 {
execsql {
CREATE TABLE t5(
a INTEGER,
CHECK( a IN (111,222,333) )
);
INSERT INTO t5 VALUES(111);
SELECT * FROM t5;
}
} {111}
do_test in-10.2 {
catchsql {
INSERT INTO t5 VALUES(4);
}
} {1 {constraint failed}}
# Ticket #1821
#
# Type affinity applied to the right-hand side of an IN operator.
#
do_test in-11.1 {
execsql {
CREATE TABLE t6(a,b NUMERIC);
INSERT INTO t6 VALUES(1,2);
INSERT INTO t6 VALUES(2,3);
SELECT * FROM t6 WHERE b IN (2);
}
} {1 2}
do_test in-11.2 {
# The '2' should be coerced into 2 because t6.b is NUMERIC
execsql {
SELECT * FROM t6 WHERE b IN ('2');
}
} {1 2}
do_test in-11.3 {
# No coercion should occur here because of the unary + before b.
execsql {
SELECT * FROM t6 WHERE +b IN ('2');
}
} {}
do_test in-11.4 {
# No coercion because column a as affinity NONE
execsql {
SELECT * FROM t6 WHERE a IN ('2');
}
} {}
do_test in-11.5 {
execsql {
SELECT * FROM t6 WHERE a IN (2);
}
} {2 3}
do_test in-11.6 {
# No coercion because column a as affinity NONE
execsql {
SELECT * FROM t6 WHERE +a IN ('2');
}
} {}
finish_test
+711
View File
@@ -0,0 +1,711 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the CREATE INDEX statement.
#
# $Id: index.test,v 1.42 2006/03/29 00:24:07 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a basic index and verify it is added to sqlite_master
#
do_test index-1.1 {
execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
execsql {CREATE INDEX index1 ON test1(f1)}
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {index1 test1}
do_test index-1.1b {
execsql {SELECT name, sql, tbl_name, type FROM sqlite_master
WHERE name='index1'}
} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index}
do_test index-1.1c {
db close
sqlite3 db test.db
execsql {SELECT name, sql, tbl_name, type FROM sqlite_master
WHERE name='index1'}
} {index1 {CREATE INDEX index1 ON test1(f1)} test1 index}
do_test index-1.1d {
db close
sqlite3 db test.db
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {index1 test1}
# Verify that the index dies with the table
#
do_test index-1.2 {
execsql {DROP TABLE test1}
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {}
# Try adding an index to a table that does not exist
#
do_test index-2.1 {
set v [catch {execsql {CREATE INDEX index1 ON test1(f1)}} msg]
lappend v $msg
} {1 {no such table: main.test1}}
# Try adding an index on a column of a table where the table
# exists but the column does not.
#
do_test index-2.1 {
execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg]
lappend v $msg
} {1 {table test1 has no column named f4}}
# Try an index with some columns that match and others that do now.
#
do_test index-2.2 {
set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg]
execsql {DROP TABLE test1}
lappend v $msg
} {1 {table test1 has no column named f4}}
# Try creating a bunch of indices on the same table
#
set r {}
for {set i 1} {$i<100} {incr i} {
lappend r [format index%02d $i]
}
do_test index-3.1 {
execsql {CREATE TABLE test1(f1 int, f2 int, f3 int, f4 int, f5 int)}
for {set i 1} {$i<100} {incr i} {
set sql "CREATE INDEX [format index%02d $i] ON test1(f[expr {($i%5)+1}])"
execsql $sql
}
execsql {SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='test1'
ORDER BY name}
} $r
integrity_check index-3.2.1
ifcapable {reindex} {
do_test index-3.2.2 {
execsql REINDEX
} {}
}
integrity_check index-3.2.3
# Verify that all the indices go away when we drop the table.
#
do_test index-3.3 {
execsql {DROP TABLE test1}
execsql {SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='test1'
ORDER BY name}
} {}
# Create a table and insert values into that table. Then create
# an index on that table. Verify that we can select values
# from the table correctly using the index.
#
# Note that the index names "index9" and "indext" are chosen because
# they both have the same hash.
#
do_test index-4.1 {
execsql {CREATE TABLE test1(cnt int, power int)}
for {set i 1} {$i<20} {incr i} {
execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
}
execsql {CREATE INDEX index9 ON test1(cnt)}
execsql {CREATE INDEX indext ON test1(power)}
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {index9 indext test1}
do_test index-4.2 {
execsql {SELECT cnt FROM test1 WHERE power=4}
} {2}
do_test index-4.3 {
execsql {SELECT cnt FROM test1 WHERE power=1024}
} {10}
do_test index-4.4 {
execsql {SELECT power FROM test1 WHERE cnt=6}
} {64}
do_test index-4.5 {
execsql {DROP INDEX indext}
execsql {SELECT power FROM test1 WHERE cnt=6}
} {64}
do_test index-4.6 {
execsql {SELECT cnt FROM test1 WHERE power=1024}
} {10}
do_test index-4.7 {
execsql {CREATE INDEX indext ON test1(cnt)}
execsql {SELECT power FROM test1 WHERE cnt=6}
} {64}
do_test index-4.8 {
execsql {SELECT cnt FROM test1 WHERE power=1024}
} {10}
do_test index-4.9 {
execsql {DROP INDEX index9}
execsql {SELECT power FROM test1 WHERE cnt=6}
} {64}
do_test index-4.10 {
execsql {SELECT cnt FROM test1 WHERE power=1024}
} {10}
do_test index-4.11 {
execsql {DROP INDEX indext}
execsql {SELECT power FROM test1 WHERE cnt=6}
} {64}
do_test index-4.12 {
execsql {SELECT cnt FROM test1 WHERE power=1024}
} {10}
do_test index-4.13 {
execsql {DROP TABLE test1}
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {}
integrity_check index-4.14
# Do not allow indices to be added to sqlite_master
#
do_test index-5.1 {
set v [catch {execsql {CREATE INDEX index1 ON sqlite_master(name)}} msg]
lappend v $msg
} {1 {table sqlite_master may not be indexed}}
do_test index-5.2 {
execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
} {}
# Do not allow indices with duplicate names to be added
#
do_test index-6.1 {
execsql {CREATE TABLE test1(f1 int, f2 int)}
execsql {CREATE TABLE test2(g1 real, g2 real)}
execsql {CREATE INDEX index1 ON test1(f1)}
set v [catch {execsql {CREATE INDEX index1 ON test2(g1)}} msg]
lappend v $msg
} {1 {index index1 already exists}}
do_test index-6.1.1 {
catchsql {CREATE INDEX [index1] ON test2(g1)}
} {1 {index index1 already exists}}
do_test index-6.1b {
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {index1 test1 test2}
do_test index-6.1c {
catchsql {CREATE INDEX IF NOT EXISTS index1 ON test1(f1)}
} {0 {}}
do_test index-6.2 {
set v [catch {execsql {CREATE INDEX test1 ON test2(g1)}} msg]
lappend v $msg
} {1 {there is already a table named test1}}
do_test index-6.2b {
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {index1 test1 test2}
do_test index-6.3 {
execsql {DROP TABLE test1}
execsql {DROP TABLE test2}
execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name}
} {}
do_test index-6.4 {
execsql {
CREATE TABLE test1(a,b);
CREATE INDEX index1 ON test1(a);
CREATE INDEX index2 ON test1(b);
CREATE INDEX index3 ON test1(a,b);
DROP TABLE test1;
SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name;
}
} {}
integrity_check index-6.5
# Create a primary key
#
do_test index-7.1 {
execsql {CREATE TABLE test1(f1 int, f2 int primary key)}
for {set i 1} {$i<20} {incr i} {
execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])"
}
execsql {SELECT count(*) FROM test1}
} {19}
do_test index-7.2 {
execsql {SELECT f1 FROM test1 WHERE f2=65536}
} {16}
do_test index-7.3 {
execsql {
SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='test1'
}
} {sqlite_autoindex_test1_1}
do_test index-7.4 {
execsql {DROP table test1}
execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
} {}
integrity_check index-7.5
# Make sure we cannot drop a non-existant index.
#
do_test index-8.1 {
set v [catch {execsql {DROP INDEX index1}} msg]
lappend v $msg
} {1 {no such index: index1}}
# Make sure we don't actually create an index when the EXPLAIN keyword
# is used.
#
do_test index-9.1 {
execsql {CREATE TABLE tab1(a int)}
ifcapable {explain} {
execsql {EXPLAIN CREATE INDEX idx1 ON tab1(a)}
}
execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1'}
} {tab1}
do_test index-9.2 {
execsql {CREATE INDEX idx1 ON tab1(a)}
execsql {SELECT name FROM sqlite_master WHERE tbl_name='tab1' ORDER BY name}
} {idx1 tab1}
integrity_check index-9.3
# Allow more than one entry with the same key.
#
do_test index-10.0 {
execsql {
CREATE TABLE t1(a int, b int);
CREATE INDEX i1 ON t1(a);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(2,4);
INSERT INTO t1 VALUES(3,8);
INSERT INTO t1 VALUES(1,12);
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {2 12}
do_test index-10.1 {
execsql {
SELECT b FROM t1 WHERE a=2 ORDER BY b;
}
} {4}
do_test index-10.2 {
execsql {
DELETE FROM t1 WHERE b=12;
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {2}
do_test index-10.3 {
execsql {
DELETE FROM t1 WHERE b=2;
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {}
do_test index-10.4 {
execsql {
DELETE FROM t1;
INSERT INTO t1 VALUES (1,1);
INSERT INTO t1 VALUES (1,2);
INSERT INTO t1 VALUES (1,3);
INSERT INTO t1 VALUES (1,4);
INSERT INTO t1 VALUES (1,5);
INSERT INTO t1 VALUES (1,6);
INSERT INTO t1 VALUES (1,7);
INSERT INTO t1 VALUES (1,8);
INSERT INTO t1 VALUES (1,9);
INSERT INTO t1 VALUES (2,0);
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {1 2 3 4 5 6 7 8 9}
do_test index-10.5 {
ifcapable subquery {
execsql { DELETE FROM t1 WHERE b IN (2, 4, 6, 8); }
} else {
execsql { DELETE FROM t1 WHERE b = 2 OR b = 4 OR b = 6 OR b = 8; }
}
execsql {
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {1 3 5 7 9}
do_test index-10.6 {
execsql {
DELETE FROM t1 WHERE b>2;
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {1}
do_test index-10.7 {
execsql {
DELETE FROM t1 WHERE b=1;
SELECT b FROM t1 WHERE a=1 ORDER BY b;
}
} {}
do_test index-10.8 {
execsql {
SELECT b FROM t1 ORDER BY b;
}
} {0}
integrity_check index-10.9
# Automatically create an index when we specify a primary key.
#
do_test index-11.1 {
execsql {
CREATE TABLE t3(
a text,
b int,
c float,
PRIMARY KEY(b)
);
}
for {set i 1} {$i<=50} {incr i} {
execsql "INSERT INTO t3 VALUES('x${i}x',$i,0.$i)"
}
set sqlite_search_count 0
concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
} {0.1 3}
integrity_check index-11.2
# Numeric strings should compare as if they were numbers. So even if the
# strings are not character-by-character the same, if they represent the
# same number they should compare equal to one another. Verify that this
# is true in indices.
#
# Updated for sqlite3 v3: SQLite will now store these values as numbers
# (because the affinity of column a is NUMERIC) so the quirky
# representations are not retained. i.e. '+1.0' becomes '1'.
do_test index-12.1 {
execsql {
CREATE TABLE t4(a NUM,b);
INSERT INTO t4 VALUES('0.0',1);
INSERT INTO t4 VALUES('0.00',2);
INSERT INTO t4 VALUES('abc',3);
INSERT INTO t4 VALUES('-1.0',4);
INSERT INTO t4 VALUES('+1.0',5);
INSERT INTO t4 VALUES('0',6);
INSERT INTO t4 VALUES('00000',7);
SELECT a FROM t4 ORDER BY b;
}
} {0 0 abc -1 1 0 0}
do_test index-12.2 {
execsql {
SELECT a FROM t4 WHERE a==0 ORDER BY b
}
} {0 0 0 0}
do_test index-12.3 {
execsql {
SELECT a FROM t4 WHERE a<0.5 ORDER BY b
}
} {0 0 -1 0 0}
do_test index-12.4 {
execsql {
SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
}
} {0 0 abc 1 0 0}
do_test index-12.5 {
execsql {
CREATE INDEX t4i1 ON t4(a);
SELECT a FROM t4 WHERE a==0 ORDER BY b
}
} {0 0 0 0}
do_test index-12.6 {
execsql {
SELECT a FROM t4 WHERE a<0.5 ORDER BY b
}
} {0 0 -1 0 0}
do_test index-12.7 {
execsql {
SELECT a FROM t4 WHERE a>-0.5 ORDER BY b
}
} {0 0 abc 1 0 0}
integrity_check index-12.8
# Make sure we cannot drop an automatically created index.
#
do_test index-13.1 {
execsql {
CREATE TABLE t5(
a int UNIQUE,
b float PRIMARY KEY,
c varchar(10),
UNIQUE(a,c)
);
INSERT INTO t5 VALUES(1,2,3);
SELECT * FROM t5;
}
} {1 2.0 3}
do_test index-13.2 {
set ::idxlist [execsql {
SELECT name FROM sqlite_master WHERE type="index" AND tbl_name="t5";
}]
llength $::idxlist
} {3}
for {set i 0} {$i<[llength $::idxlist]} {incr i} {
do_test index-13.3.$i {
catchsql "
DROP INDEX '[lindex $::idxlist $i]';
"
} {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}}
}
do_test index-13.4 {
execsql {
INSERT INTO t5 VALUES('a','b','c');
SELECT * FROM t5;
}
} {1 2.0 3 a b c}
integrity_check index-13.5
# Check the sort order of data in an index.
#
do_test index-14.1 {
execsql {
CREATE TABLE t6(a,b,c);
CREATE INDEX t6i1 ON t6(a,b);
INSERT INTO t6 VALUES('','',1);
INSERT INTO t6 VALUES('',NULL,2);
INSERT INTO t6 VALUES(NULL,'',3);
INSERT INTO t6 VALUES('abc',123,4);
INSERT INTO t6 VALUES(123,'abc',5);
SELECT c FROM t6 ORDER BY a,b;
}
} {3 5 2 1 4}
do_test index-14.2 {
execsql {
SELECT c FROM t6 WHERE a='';
}
} {2 1}
do_test index-14.3 {
execsql {
SELECT c FROM t6 WHERE b='';
}
} {1 3}
do_test index-14.4 {
execsql {
SELECT c FROM t6 WHERE a>'';
}
} {4}
do_test index-14.5 {
execsql {
SELECT c FROM t6 WHERE a>='';
}
} {2 1 4}
do_test index-14.6 {
execsql {
SELECT c FROM t6 WHERE a>123;
}
} {2 1 4}
do_test index-14.7 {
execsql {
SELECT c FROM t6 WHERE a>=123;
}
} {5 2 1 4}
do_test index-14.8 {
execsql {
SELECT c FROM t6 WHERE a<'abc';
}
} {5 2 1}
do_test index-14.9 {
execsql {
SELECT c FROM t6 WHERE a<='abc';
}
} {5 2 1 4}
do_test index-14.10 {
execsql {
SELECT c FROM t6 WHERE a<='';
}
} {5 2 1}
do_test index-14.11 {
execsql {
SELECT c FROM t6 WHERE a<'';
}
} {5}
integrity_check index-14.12
do_test index-15.1 {
execsql {
DELETE FROM t1;
SELECT * FROM t1;
}
} {}
do_test index-15.2 {
execsql {
INSERT INTO t1 VALUES('1.234e5',1);
INSERT INTO t1 VALUES('12.33e04',2);
INSERT INTO t1 VALUES('12.35E4',3);
INSERT INTO t1 VALUES('12.34e',4);
INSERT INTO t1 VALUES('12.32e+4',5);
INSERT INTO t1 VALUES('12.36E+04',6);
INSERT INTO t1 VALUES('12.36E+',7);
INSERT INTO t1 VALUES('+123.10000E+0003',8);
INSERT INTO t1 VALUES('+',9);
INSERT INTO t1 VALUES('+12347.E+02',10);
INSERT INTO t1 VALUES('+12347E+02',11);
SELECT b FROM t1 ORDER BY a;
}
} {8 5 2 1 3 6 11 9 10 4 7}
integrity_check index-15.1
# The following tests - index-16.* - test that when a table definition
# includes qualifications that specify the same constraint twice only a
# single index is generated to enforce the constraint.
#
# For example: "CREATE TABLE abc( x PRIMARY KEY, UNIQUE(x) );"
#
do_test index-16.1 {
execsql {
CREATE TABLE t7(c UNIQUE PRIMARY KEY);
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.2 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c UNIQUE PRIMARY KEY);
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.3 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c PRIMARY KEY, UNIQUE(c) );
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.4 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c, d , UNIQUE(c, d), PRIMARY KEY(c, d) );
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {1}
do_test index-16.5 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c, d , UNIQUE(c), PRIMARY KEY(c, d) );
SELECT count(*) FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {2}
# Test that automatically create indices are named correctly. The current
# convention is: "sqlite_autoindex_<table name>_<integer>"
#
# Then check that it is an error to try to drop any automtically created
# indices.
do_test index-17.1 {
execsql {
DROP TABLE t7;
CREATE TABLE t7(c, d UNIQUE, UNIQUE(c), PRIMARY KEY(c, d) );
SELECT name FROM sqlite_master WHERE tbl_name = 't7' AND type = 'index';
}
} {sqlite_autoindex_t7_1 sqlite_autoindex_t7_2 sqlite_autoindex_t7_3}
do_test index-17.2 {
catchsql {
DROP INDEX sqlite_autoindex_t7_1;
}
} {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}}
do_test index-17.3 {
catchsql {
DROP INDEX IF EXISTS sqlite_autoindex_t7_1;
}
} {1 {index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped}}
do_test index-17.4 {
catchsql {
DROP INDEX IF EXISTS no_such_index;
}
} {0 {}}
# The following tests ensure that it is not possible to explicitly name
# a schema object with a name beginning with "sqlite_". Granted that is a
# little outside the focus of this test scripts, but this has got to be
# tested somewhere.
do_test index-18.1 {
catchsql {
CREATE TABLE sqlite_t1(a, b, c);
}
} {1 {object name reserved for internal use: sqlite_t1}}
do_test index-18.2 {
catchsql {
CREATE INDEX sqlite_i1 ON t7(c);
}
} {1 {object name reserved for internal use: sqlite_i1}}
ifcapable view {
do_test index-18.3 {
catchsql {
CREATE VIEW sqlite_v1 AS SELECT * FROM t7;
}
} {1 {object name reserved for internal use: sqlite_v1}}
} ;# ifcapable view
ifcapable {trigger} {
do_test index-18.4 {
catchsql {
CREATE TRIGGER sqlite_tr1 BEFORE INSERT ON t7 BEGIN SELECT 1; END;
}
} {1 {object name reserved for internal use: sqlite_tr1}}
}
do_test index-18.5 {
execsql {
DROP TABLE t7;
}
} {}
# These tests ensure that if multiple table definition constraints are
# implemented by a single indice, the correct ON CONFLICT policy applies.
ifcapable conflict {
do_test index-19.1 {
execsql {
CREATE TABLE t7(a UNIQUE PRIMARY KEY);
CREATE TABLE t8(a UNIQUE PRIMARY KEY ON CONFLICT ROLLBACK);
INSERT INTO t7 VALUES(1);
INSERT INTO t8 VALUES(1);
}
} {}
do_test index-19.2 {
catchsql {
BEGIN;
INSERT INTO t7 VALUES(1);
}
} {1 {column a is not unique}}
do_test index-19.3 {
catchsql {
BEGIN;
}
} {1 {cannot start a transaction within a transaction}}
do_test index-19.4 {
catchsql {
INSERT INTO t8 VALUES(1);
}
} {1 {column a is not unique}}
do_test index-19.5 {
catchsql {
BEGIN;
COMMIT;
}
} {0 {}}
do_test index-19.6 {
catchsql {
DROP TABLE t7;
DROP TABLE t8;
CREATE TABLE t7(
a PRIMARY KEY ON CONFLICT FAIL,
UNIQUE(a) ON CONFLICT IGNORE
);
}
} {1 {conflicting ON CONFLICT clauses specified}}
} ; # end of "ifcapable conflict" block
ifcapable {reindex} {
do_test index-19.7 {
execsql REINDEX
} {}
}
integrity_check index-19.8
# Drop index with a quoted name. Ticket #695.
#
do_test index-20.1 {
execsql {
CREATE INDEX "t6i2" ON t6(c);
DROP INDEX "t6i2";
}
} {}
do_test index-20.2 {
execsql {
DROP INDEX "t6i1";
}
} {}
finish_test
+74
View File
@@ -0,0 +1,74 @@
# 2005 January 11
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the CREATE INDEX statement.
#
# $Id: index2.test,v 1.3 2006/03/03 19:12:30 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table with a large number of columns
#
do_test index2-1.1 {
set sql {CREATE TABLE t1(}
for {set i 1} {$i<1000} {incr i} {
append sql "c$i,"
}
append sql "c1000);"
execsql $sql
} {}
do_test index2-1.2 {
set sql {INSERT INTO t1 VALUES(}
for {set i 1} {$i<1000} {incr i} {
append sql $i,
}
append sql {1000);}
execsql $sql
} {}
do_test index2-1.3 {
execsql {SELECT c123 FROM t1}
} 123
do_test index2-1.4 {
execsql BEGIN
for {set j 1} {$j<=100} {incr j} {
set sql {INSERT INTO t1 VALUES(}
for {set i 1} {$i<1000} {incr i} {
append sql [expr {$j*10000+$i}],
}
append sql "[expr {$j*10000+1000}]);"
execsql $sql
}
execsql COMMIT
execsql {SELECT count(*) FROM t1}
} 101
do_test index2-1.5 {
execsql {SELECT round(sum(c1000)) FROM t1}
} {50601000.0}
# Create indices with many columns
#
do_test index2-2.1 {
set sql "CREATE INDEX t1i1 ON t1("
for {set i 1} {$i<1000} {incr i} {
append sql c$i,
}
append sql c1000)
execsql $sql
} {}
do_test index2-2.2 {
ifcapable explain {
execsql {EXPLAIN SELECT c9 FROM t1 ORDER BY c1, c2, c3, c4, c5}
}
execsql {SELECT c9 FROM t1 ORDER BY c1, c2, c3, c4, c5, c6 LIMIT 5}
} {9 10009 20009 30009 40009}
finish_test
+58
View File
@@ -0,0 +1,58 @@
# 2005 February 14
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the CREATE INDEX statement.
#
# $Id: index3.test,v 1.2 2005/08/20 03:03:04 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Ticket #1115. Make sure that when a UNIQUE index is created on a
# non-unique column (or columns) that it fails and that it leaves no
# residue behind.
#
do_test index3-1.1 {
execsql {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(1);
SELECT * FROM t1;
}
} {1 1}
do_test index3-1.2 {
catchsql {
BEGIN;
CREATE UNIQUE INDEX i1 ON t1(a);
}
} {1 {indexed columns are not unique}}
do_test index3-1.3 {
catchsql COMMIT;
} {0 {}}
integrity_check index3-1.4
# This test corrupts the database file so it must be the last test
# in the series.
#
do_test index3-99.1 {
execsql {
PRAGMA writable_schema=on;
UPDATE sqlite_master SET sql='nonsense';
}
db close
sqlite3 db test.db
catchsql {
DROP INDEX i1;
}
} {1 {malformed database schema - near "nonsense": syntax error}}
finish_test
+368
View File
@@ -0,0 +1,368 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the INSERT statement.
#
# $Id: insert.test,v 1.30 2006/06/11 23:41:56 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Try to insert into a non-existant table.
#
do_test insert-1.1 {
set v [catch {execsql {INSERT INTO test1 VALUES(1,2,3)}} msg]
lappend v $msg
} {1 {no such table: test1}}
# Try to insert into sqlite_master
#
do_test insert-1.2 {
set v [catch {execsql {INSERT INTO sqlite_master VALUES(1,2,3,4)}} msg]
lappend v $msg
} {1 {table sqlite_master may not be modified}}
# Try to insert the wrong number of entries.
#
do_test insert-1.3 {
execsql {CREATE TABLE test1(one int, two int, three int)}
set v [catch {execsql {INSERT INTO test1 VALUES(1,2)}} msg]
lappend v $msg
} {1 {table test1 has 3 columns but 2 values were supplied}}
do_test insert-1.3b {
set v [catch {execsql {INSERT INTO test1 VALUES(1,2,3,4)}} msg]
lappend v $msg
} {1 {table test1 has 3 columns but 4 values were supplied}}
do_test insert-1.3c {
set v [catch {execsql {INSERT INTO test1(one,two) VALUES(1,2,3,4)}} msg]
lappend v $msg
} {1 {4 values for 2 columns}}
do_test insert-1.3d {
set v [catch {execsql {INSERT INTO test1(one,two) VALUES(1)}} msg]
lappend v $msg
} {1 {1 values for 2 columns}}
# Try to insert into a non-existant column of a table.
#
do_test insert-1.4 {
set v [catch {execsql {INSERT INTO test1(one,four) VALUES(1,2)}} msg]
lappend v $msg
} {1 {table test1 has no column named four}}
# Make sure the inserts actually happen
#
do_test insert-1.5 {
execsql {INSERT INTO test1 VALUES(1,2,3)}
execsql {SELECT * FROM test1}
} {1 2 3}
do_test insert-1.5b {
execsql {INSERT INTO test1 VALUES(4,5,6)}
execsql {SELECT * FROM test1 ORDER BY one}
} {1 2 3 4 5 6}
do_test insert-1.5c {
execsql {INSERT INTO test1 VALUES(7,8,9)}
execsql {SELECT * FROM test1 ORDER BY one}
} {1 2 3 4 5 6 7 8 9}
do_test insert-1.6 {
execsql {DELETE FROM test1}
execsql {INSERT INTO test1(one,two) VALUES(1,2)}
execsql {SELECT * FROM test1 ORDER BY one}
} {1 2 {}}
do_test insert-1.6b {
execsql {INSERT INTO test1(two,three) VALUES(5,6)}
execsql {SELECT * FROM test1 ORDER BY one}
} {{} 5 6 1 2 {}}
do_test insert-1.6c {
execsql {INSERT INTO test1(three,one) VALUES(7,8)}
execsql {SELECT * FROM test1 ORDER BY one}
} {{} 5 6 1 2 {} 8 {} 7}
# A table to use for testing default values
#
do_test insert-2.1 {
execsql {
CREATE TABLE test2(
f1 int default -111,
f2 real default +4.32,
f3 int default +222,
f4 int default 7.89
)
}
execsql {SELECT * from test2}
} {}
do_test insert-2.2 {
execsql {INSERT INTO test2(f1,f3) VALUES(+10,-10)}
execsql {SELECT * FROM test2}
} {10 4.32 -10 7.89}
do_test insert-2.3 {
execsql {INSERT INTO test2(f2,f4) VALUES(1.23,-3.45)}
execsql {SELECT * FROM test2 WHERE f1==-111}
} {-111 1.23 222 -3.45}
do_test insert-2.4 {
execsql {INSERT INTO test2(f1,f2,f4) VALUES(77,+1.23,3.45)}
execsql {SELECT * FROM test2 WHERE f1==77}
} {77 1.23 222 3.45}
do_test insert-2.10 {
execsql {
DROP TABLE test2;
CREATE TABLE test2(
f1 int default 111,
f2 real default -4.32,
f3 text default hi,
f4 text default 'abc-123',
f5 varchar(10)
)
}
execsql {SELECT * from test2}
} {}
do_test insert-2.11 {
execsql {INSERT INTO test2(f2,f4) VALUES(-2.22,'hi!')}
execsql {SELECT * FROM test2}
} {111 -2.22 hi hi! {}}
do_test insert-2.12 {
execsql {INSERT INTO test2(f1,f5) VALUES(1,'xyzzy')}
execsql {SELECT * FROM test2 ORDER BY f1}
} {1 -4.32 hi abc-123 xyzzy 111 -2.22 hi hi! {}}
# Do additional inserts with default values, but this time
# on a table that has indices. In particular we want to verify
# that the correct default values are inserted into the indices.
#
do_test insert-3.1 {
execsql {
DELETE FROM test2;
CREATE INDEX index9 ON test2(f1,f2);
CREATE INDEX indext ON test2(f4,f5);
SELECT * from test2;
}
} {}
# Update for sqlite3 v3:
# Change the 111 to '111' in the following two test cases, because
# the default value is being inserted as a string. TODO: It shouldn't be.
do_test insert-3.2 {
execsql {INSERT INTO test2(f2,f4) VALUES(-3.33,'hum')}
execsql {SELECT * FROM test2 WHERE f1='111' AND f2=-3.33}
} {111 -3.33 hi hum {}}
do_test insert-3.3 {
execsql {INSERT INTO test2(f1,f2,f5) VALUES(22,-4.44,'wham')}
execsql {SELECT * FROM test2 WHERE f1='111' AND f2=-3.33}
} {111 -3.33 hi hum {}}
do_test insert-3.4 {
execsql {SELECT * FROM test2 WHERE f1=22 AND f2=-4.44}
} {22 -4.44 hi abc-123 wham}
ifcapable {reindex} {
do_test insert-3.5 {
execsql REINDEX
} {}
}
integrity_check insert-3.5
# Test of expressions in the VALUES clause
#
do_test insert-4.1 {
execsql {
CREATE TABLE t3(a,b,c);
INSERT INTO t3 VALUES(1+2+3,4,5);
SELECT * FROM t3;
}
} {6 4 5}
do_test insert-4.2 {
ifcapable subquery {
execsql {INSERT INTO t3 VALUES((SELECT max(a) FROM t3)+1,5,6);}
} else {
set maxa [execsql {SELECT max(a) FROM t3}]
execsql "INSERT INTO t3 VALUES($maxa+1,5,6);"
}
execsql {
SELECT * FROM t3 ORDER BY a;
}
} {6 4 5 7 5 6}
ifcapable subquery {
do_test insert-4.3 {
catchsql {
INSERT INTO t3 VALUES((SELECT max(a) FROM t3)+1,t3.a,6);
SELECT * FROM t3 ORDER BY a;
}
} {1 {no such column: t3.a}}
}
do_test insert-4.4 {
ifcapable subquery {
execsql {INSERT INTO t3 VALUES((SELECT b FROM t3 WHERE a=0),6,7);}
} else {
set b [execsql {SELECT b FROM t3 WHERE a = 0}]
if {$b==""} {set b NULL}
execsql "INSERT INTO t3 VALUES($b,6,7);"
}
execsql {
SELECT * FROM t3 ORDER BY a;
}
} {{} 6 7 6 4 5 7 5 6}
do_test insert-4.5 {
execsql {
SELECT b,c FROM t3 WHERE a IS NULL;
}
} {6 7}
do_test insert-4.6 {
catchsql {
INSERT INTO t3 VALUES(notafunc(2,3),2,3);
}
} {1 {no such function: notafunc}}
do_test insert-4.7 {
execsql {
INSERT INTO t3 VALUES(min(1,2,3),max(1,2,3),99);
SELECT * FROM t3 WHERE c=99;
}
} {1 3 99}
# Test the ability to insert from a temporary table into itself.
# Ticket #275.
#
ifcapable tempdb {
do_test insert-5.1 {
execsql {
CREATE TEMP TABLE t4(x);
INSERT INTO t4 VALUES(1);
SELECT * FROM t4;
}
} {1}
do_test insert-5.2 {
execsql {
INSERT INTO t4 SELECT x+1 FROM t4;
SELECT * FROM t4;
}
} {1 2}
ifcapable {explain} {
do_test insert-5.3 {
# verify that a temporary table is used to copy t4 to t4
set x [execsql {
EXPLAIN INSERT INTO t4 SELECT x+2 FROM t4;
}]
expr {[lsearch $x OpenEphemeral]>0}
} {1}
}
do_test insert-5.4 {
# Verify that table "test1" begins on page 3. This should be the same
# page number used by "t4" above.
#
# Update for v3 - the first table now begins on page 2 of each file, not 3.
execsql {
SELECT rootpage FROM sqlite_master WHERE name='test1';
}
} [expr $AUTOVACUUM?3:2]
do_test insert-5.5 {
# Verify that "t4" begins on page 3.
#
# Update for v3 - the first table now begins on page 2 of each file, not 3.
execsql {
SELECT rootpage FROM sqlite_temp_master WHERE name='t4';
}
} {2}
do_test insert-5.6 {
# This should not use an intermediate temporary table.
execsql {
INSERT INTO t4 SELECT one FROM test1 WHERE three=7;
SELECT * FROM t4
}
} {1 2 8}
ifcapable {explain} {
do_test insert-5.7 {
# verify that no temporary table is used to copy test1 to t4
set x [execsql {
EXPLAIN INSERT INTO t4 SELECT one FROM test1;
}]
expr {[lsearch $x OpenTemp]>0}
} {0}
}
}
# Ticket #334: REPLACE statement corrupting indices.
#
ifcapable conflict {
# The REPLACE command is not available if SQLITE_OMIT_CONFLICT is
# defined at compilation time.
do_test insert-6.1 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
INSERT INTO t1 VALUES(1,2);
INSERT INTO t1 VALUES(2,3);
SELECT b FROM t1 WHERE b=2;
}
} {2}
do_test insert-6.2 {
execsql {
REPLACE INTO t1 VALUES(1,4);
SELECT b FROM t1 WHERE b=2;
}
} {}
do_test insert-6.3 {
execsql {
UPDATE OR REPLACE t1 SET a=2 WHERE b=4;
SELECT * FROM t1 WHERE b=4;
}
} {2 4}
do_test insert-6.4 {
execsql {
SELECT * FROM t1 WHERE b=3;
}
} {}
ifcapable {reindex} {
do_test insert-6.5 {
execsql REINDEX
} {}
}
do_test insert-6.6 {
execsql {
DROP TABLE t1;
}
} {}
}
# Test that the special optimization for queries of the form
# "SELECT max(x) FROM tbl" where there is an index on tbl(x) works with
# INSERT statments.
do_test insert-7.1 {
execsql {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
CREATE INDEX i1 ON t1(a);
}
} {}
do_test insert-7.2 {
execsql {
INSERT INTO t1 SELECT max(a) FROM t1;
}
} {}
do_test insert-7.3 {
execsql {
SELECT a FROM t1;
}
} {1 2 2}
# Ticket #1140: Check for an infinite loop in the algorithm that tests
# to see if the right-hand side of an INSERT...SELECT references the left-hand
# side.
#
ifcapable subquery&&compound {
do_test insert-8.1 {
execsql {
INSERT INTO t3 SELECT * FROM (SELECT * FROM t3 UNION ALL SELECT 1,2,3)
}
} {}
}
integrity_check insert-99.0
finish_test
+278
View File
@@ -0,0 +1,278 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the INSERT statement that takes is
# result from a SELECT.
#
# $Id: insert2.test,v 1.18 2005/10/05 11:35:09 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create some tables with data that we can select against
#
do_test insert2-1.0 {
execsql {CREATE TABLE d1(n int, log int);}
for {set i 1} {$i<=20} {incr i} {
for {set j 0} {pow(2,$j)<$i} {incr j} {}
execsql "INSERT INTO d1 VALUES($i,$j)"
}
execsql {SELECT * FROM d1 ORDER BY n}
} {1 0 2 1 3 2 4 2 5 3 6 3 7 3 8 3 9 4 10 4 11 4 12 4 13 4 14 4 15 4 16 4 17 5 18 5 19 5 20 5}
# Insert into a new table from the old one.
#
do_test insert2-1.1.1 {
execsql {
CREATE TABLE t1(log int, cnt int);
PRAGMA count_changes=on;
}
ifcapable explain {
execsql {
EXPLAIN INSERT INTO t1 SELECT log, count(*) FROM d1 GROUP BY log;
}
}
execsql {
INSERT INTO t1 SELECT log, count(*) FROM d1 GROUP BY log;
}
} {6}
do_test insert2-1.1.2 {
db changes
} {6}
do_test insert2-1.1.3 {
execsql {SELECT * FROM t1 ORDER BY log}
} {0 1 1 1 2 2 3 4 4 8 5 4}
ifcapable compound {
do_test insert2-1.2.1 {
catch {execsql {DROP TABLE t1}}
execsql {
CREATE TABLE t1(log int, cnt int);
INSERT INTO t1
SELECT log, count(*) FROM d1 GROUP BY log
EXCEPT SELECT n-1,log FROM d1;
}
} {4}
do_test insert2-1.2.2 {
execsql {
SELECT * FROM t1 ORDER BY log;
}
} {0 1 3 4 4 8 5 4}
do_test insert2-1.3.1 {
catch {execsql {DROP TABLE t1}}
execsql {
CREATE TABLE t1(log int, cnt int);
PRAGMA count_changes=off;
INSERT INTO t1
SELECT log, count(*) FROM d1 GROUP BY log
INTERSECT SELECT n-1,log FROM d1;
}
} {}
do_test insert2-1.3.2 {
execsql {
SELECT * FROM t1 ORDER BY log;
}
} {1 1 2 2}
} ;# ifcapable compound
execsql {PRAGMA count_changes=off;}
do_test insert2-1.4 {
catch {execsql {DROP TABLE t1}}
set r [execsql {
CREATE TABLE t1(log int, cnt int);
CREATE INDEX i1 ON t1(log);
CREATE INDEX i2 ON t1(cnt);
INSERT INTO t1 SELECT log, count() FROM d1 GROUP BY log;
SELECT * FROM t1 ORDER BY log;
}]
lappend r [execsql {SELECT cnt FROM t1 WHERE log=3}]
lappend r [execsql {SELECT log FROM t1 WHERE cnt=4 ORDER BY log}]
} {0 1 1 1 2 2 3 4 4 8 5 4 4 {3 5}}
do_test insert2-2.0 {
execsql {
CREATE TABLE t3(a,b,c);
CREATE TABLE t4(x,y);
INSERT INTO t4 VALUES(1,2);
SELECT * FROM t4;
}
} {1 2}
do_test insert2-2.1 {
execsql {
INSERT INTO t3(a,c) SELECT * FROM t4;
SELECT * FROM t3;
}
} {1 {} 2}
do_test insert2-2.2 {
execsql {
DELETE FROM t3;
INSERT INTO t3(c,b) SELECT * FROM t4;
SELECT * FROM t3;
}
} {{} 2 1}
do_test insert2-2.3 {
execsql {
DELETE FROM t3;
INSERT INTO t3(c,a,b) SELECT x, 'hi', y FROM t4;
SELECT * FROM t3;
}
} {hi 2 1}
integrity_check insert2-3.0
# File table t4 with lots of data
#
do_test insert2-3.1 {
execsql {
SELECT * from t4;
}
} {1 2}
do_test insert2-3.2 {
set x [db total_changes]
execsql {
BEGIN;
INSERT INTO t4 VALUES(2,4);
INSERT INTO t4 VALUES(3,6);
INSERT INTO t4 VALUES(4,8);
INSERT INTO t4 VALUES(5,10);
INSERT INTO t4 VALUES(6,12);
INSERT INTO t4 VALUES(7,14);
INSERT INTO t4 VALUES(8,16);
INSERT INTO t4 VALUES(9,18);
INSERT INTO t4 VALUES(10,20);
COMMIT;
}
expr [db total_changes] - $x
} {9}
do_test insert2-3.2.1 {
execsql {
SELECT count(*) FROM t4;
}
} {10}
do_test insert2-3.3 {
ifcapable subquery {
execsql {
BEGIN;
INSERT INTO t4 SELECT x+(SELECT max(x) FROM t4),y FROM t4;
INSERT INTO t4 SELECT x+(SELECT max(x) FROM t4),y FROM t4;
INSERT INTO t4 SELECT x+(SELECT max(x) FROM t4),y FROM t4;
INSERT INTO t4 SELECT x+(SELECT max(x) FROM t4),y FROM t4;
COMMIT;
SELECT count(*) FROM t4;
}
} else {
db function max_x_t4 {execsql {SELECT max(x) FROM t4}}
execsql {
BEGIN;
INSERT INTO t4 SELECT x+max_x_t4() ,y FROM t4;
INSERT INTO t4 SELECT x+max_x_t4() ,y FROM t4;
INSERT INTO t4 SELECT x+max_x_t4() ,y FROM t4;
INSERT INTO t4 SELECT x+max_x_t4() ,y FROM t4;
COMMIT;
SELECT count(*) FROM t4;
}
}
} {160}
do_test insert2-3.4 {
execsql {
BEGIN;
UPDATE t4 SET y='lots of data for the row where x=' || x
|| ' and y=' || y || ' - even more data to fill space';
COMMIT;
SELECT count(*) FROM t4;
}
} {160}
do_test insert2-3.5 {
ifcapable subquery {
execsql {
BEGIN;
INSERT INTO t4 SELECT x+(SELECT max(x)+1 FROM t4),y FROM t4;
SELECT count(*) from t4;
ROLLBACK;
}
} else {
execsql {
BEGIN;
INSERT INTO t4 SELECT x+max_x_t4()+1,y FROM t4;
SELECT count(*) from t4;
ROLLBACK;
}
}
} {320}
do_test insert2-3.6 {
execsql {
SELECT count(*) FROM t4;
}
} {160}
do_test insert2-3.7 {
execsql {
BEGIN;
DELETE FROM t4 WHERE x!=123;
SELECT count(*) FROM t4;
ROLLBACK;
}
} {1}
do_test insert2-3.8 {
db changes
} {159}
integrity_check insert2-3.9
# Ticket #901
#
ifcapable tempdb {
do_test insert2-4.1 {
execsql {
CREATE TABLE Dependencies(depId integer primary key,
class integer, name str, flag str);
CREATE TEMPORARY TABLE DepCheck(troveId INT, depNum INT,
flagCount INT, isProvides BOOL, class INTEGER, name STRING,
flag STRING);
INSERT INTO DepCheck
VALUES(-1, 0, 1, 0, 2, 'libc.so.6', 'GLIBC_2.0');
INSERT INTO Dependencies
SELECT DISTINCT
NULL,
DepCheck.class,
DepCheck.name,
DepCheck.flag
FROM DepCheck LEFT OUTER JOIN Dependencies ON
DepCheck.class == Dependencies.class AND
DepCheck.name == Dependencies.name AND
DepCheck.flag == Dependencies.flag
WHERE
Dependencies.depId is NULL;
};
} {}
}
#--------------------------------------------------------------------
# Test that the INSERT works when the SELECT statement (a) references
# the table being inserted into and (b) is optimized to use an index
# only.
do_test insert2-5.1 {
execsql {
CREATE TABLE t2(a, b);
INSERT INTO t2 VALUES(1, 2);
CREATE INDEX t2i1 ON t2(a);
INSERT INTO t2 SELECT a, 3 FROM t2 WHERE a = 1;
SELECT * FROM t2;
}
} {1 2 1 3}
ifcapable subquery {
do_test insert2-5.2 {
execsql {
INSERT INTO t2 SELECT (SELECT a FROM t2), 4;
SELECT * FROM t2;
}
} {1 2 1 3 1 4}
}
finish_test
+168
View File
@@ -0,0 +1,168 @@
# 2005 January 13
#
# 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 regression tests for SQLite library. The
# focus of this file is testing corner cases of the INSERT statement.
#
# $Id: insert3.test,v 1.5 2006/08/25 23:42:53 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# All the tests in this file require trigger support
#
ifcapable {trigger} {
# Create a table and a corresponding insert trigger. Do a self-insert
# into the table.
#
do_test insert3-1.0 {
execsql {
CREATE TABLE t1(a,b);
CREATE TABLE log(x UNIQUE, y);
CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
UPDATE log SET y=y+1 WHERE x=new.a;
INSERT OR IGNORE INTO log VALUES(new.a, 1);
END;
INSERT INTO t1 VALUES('hello','world');
INSERT INTO t1 VALUES(5,10);
SELECT * FROM log ORDER BY x;
}
} {5 1 hello 1}
do_test insert3-1.1 {
execsql {
INSERT INTO t1 SELECT a, b+10 FROM t1;
SELECT * FROM log ORDER BY x;
}
} {5 2 hello 2}
do_test insert3-1.2 {
execsql {
CREATE TABLE log2(x PRIMARY KEY,y);
CREATE TRIGGER r2 BEFORE INSERT ON t1 BEGIN
UPDATE log2 SET y=y+1 WHERE x=new.b;
INSERT OR IGNORE INTO log2 VALUES(new.b,1);
END;
INSERT INTO t1 VALUES(453,'hi');
SELECT * FROM log ORDER BY x;
}
} {5 2 453 1 hello 2}
do_test insert3-1.3 {
execsql {
SELECT * FROM log2 ORDER BY x;
}
} {hi 1}
ifcapable compound {
do_test insert3-1.4.1 {
execsql {
INSERT INTO t1 SELECT * FROM t1;
SELECT 'a:', x, y FROM log UNION ALL
SELECT 'b:', x, y FROM log2 ORDER BY x;
}
} {a: 5 4 b: 10 2 b: 20 1 a: 453 2 a: hello 4 b: hi 2 b: world 1}
do_test insert3-1.4.2 {
execsql {
SELECT 'a:', x, y FROM log UNION ALL
SELECT 'b:', x, y FROM log2 ORDER BY x, y;
}
} {a: 5 4 b: 10 2 b: 20 1 a: 453 2 a: hello 4 b: hi 2 b: world 1}
do_test insert3-1.5 {
execsql {
INSERT INTO t1(a) VALUES('xyz');
SELECT * FROM log ORDER BY x;
}
} {5 4 453 2 hello 4 xyz 1}
}
do_test insert3-2.1 {
execsql {
CREATE TABLE t2(
a INTEGER PRIMARY KEY,
b DEFAULT 'b',
c DEFAULT 'c'
);
CREATE TABLE t2dup(a,b,c);
CREATE TRIGGER t2r1 BEFORE INSERT ON t2 BEGIN
INSERT INTO t2dup(a,b,c) VALUES(new.a,new.b,new.c);
END;
INSERT INTO t2(a) VALUES(123);
INSERT INTO t2(b) VALUES(234);
INSERT INTO t2(c) VALUES(345);
SELECT * FROM t2dup;
}
} {123 b c -1 234 c -1 b 345}
do_test insert3-2.2 {
execsql {
DELETE FROM t2dup;
INSERT INTO t2(a) SELECT 1 FROM t1 LIMIT 1;
INSERT INTO t2(b) SELECT 987 FROM t1 LIMIT 1;
INSERT INTO t2(c) SELECT 876 FROM t1 LIMIT 1;
SELECT * FROM t2dup;
}
} {1 b c -1 987 c -1 b 876}
# Test for proper detection of malformed WHEN clauses on INSERT triggers.
#
do_test insert3-3.1 {
execsql {
CREATE TABLE t3(a,b,c);
CREATE TRIGGER t3r1 BEFORE INSERT on t3 WHEN nosuchcol BEGIN
SELECT 'illegal WHEN clause';
END;
}
} {}
do_test insert3-3.2 {
catchsql {
INSERT INTO t3 VALUES(1,2,3)
}
} {1 {no such column: nosuchcol}}
do_test insert3-3.3 {
execsql {
CREATE TABLE t4(a,b,c);
CREATE TRIGGER t4r1 AFTER INSERT on t4 WHEN nosuchcol BEGIN
SELECT 'illegal WHEN clause';
END;
}
} {}
do_test insert3-3.4 {
catchsql {
INSERT INTO t4 VALUES(1,2,3)
}
} {1 {no such column: nosuchcol}}
} ;# ifcapable {trigger}
# Tests for the INSERT INTO ... DEFAULT VALUES construct
#
do_test insert4-3.5 {
execsql {
CREATE TABLE t5(
a INTEGER PRIMARY KEY,
b DEFAULT 'xyz'
);
INSERT INTO t5 DEFAULT VALUES;
SELECT * FROM t5;
}
} {1 xyz}
do_test insert4-3.6 {
execsql {
INSERT INTO t5 DEFAULT VALUES;
SELECT * FROM t5;
}
} {1 xyz 2 xyz}
do_test insert4-3.7 {
execsql {
CREATE TABLE t6(x,y DEFAULT 4.3, z DEFAULT x'6869');
INSERT INTO t6 DEFAULT VALUES;
SELECT * FROM t6;
}
} {{} 4.3 hi}
finish_test
+197
View File
@@ -0,0 +1,197 @@
# 2004 Feb 8
#
# 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 regression tests for SQLite library. The
# focus of this script is the sqlite_interrupt() API.
#
# $Id: interrupt.test,v 1.13 2006/07/17 00:02:46 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set DB [sqlite3_connection_pointer db]
# Compute a checksum on the entire database.
#
proc cksum {{db db}} {
set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n
foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
append txt [$db eval "SELECT * FROM $tbl"]\n
}
foreach prag {default_synchronous default_cache_size} {
append txt $prag-[$db eval "PRAGMA $prag"]\n
}
set cksum [string length $txt]-[md5 $txt]
# puts $cksum-[file size test.db]
return $cksum
}
# This routine attempts to execute the sql in $sql. It triggers an
# interrupt at progressively later and later points during the processing
# and checks to make sure SQLITE_INTERRUPT is returned. Eventually,
# the routine completes successfully.
#
proc interrupt_test {testid sql result {initcnt 0}} {
set orig_sum [cksum]
set i $initcnt
while 1 {
incr i
set ::sqlite_interrupt_count $i
do_test $testid.$i.1 [format {
set ::r [catchsql %s]
set ::code [db errorcode]
expr {$::code==0 || $::code==9}
} [list $sql]] 1
if {$::code==9} {
do_test $testid.$i.2 {
cksum
} $orig_sum
} else {
do_test $testid.$i.99 {
set ::r
} [list 0 $result]
break
}
}
set ::sqlite_interrupt_count 0
}
do_test interrupt-1.1 {
execsql {
CREATE TABLE t1(a,b);
SELECT name FROM sqlite_master;
}
} {t1}
interrupt_test interrupt-1.2 {DROP TABLE t1} {}
do_test interrupt-1.3 {
execsql {
SELECT name FROM sqlite_master;
}
} {}
integrity_check interrupt-1.4
do_test interrrupt-2.1 {
execsql {
BEGIN;
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,randstr(300,400));
INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1;
INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1;
INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1;
INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1;
INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1;
INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1;
COMMIT;
UPDATE t1 SET b=substr(b,-5,5);
SELECT count(*) from t1;
}
} 64
set origsize [file size test.db]
set cksum [db eval {SELECT md5sum(a || b) FROM t1}]
ifcapable {vacuum} {
interrupt_test interrupt-2.2 {VACUUM} {} 100
}
do_test interrupt-2.3 {
execsql {
SELECT md5sum(a || b) FROM t1;
}
} $cksum
ifcapable {vacuum && !default_autovacuum} {
do_test interrupt-2.4 {
expr {$::origsize>[file size test.db]}
} 1
}
ifcapable {explain} {
do_test interrupt-2.5 {
set sql {EXPLAIN SELECT max(a,b), a, b FROM t1}
execsql $sql
set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg]
lappend rc $msg
} {1 interrupted}
}
integrity_check interrupt-2.6
# Ticket #594. If an interrupt occurs in the middle of a transaction
# and that transaction is later rolled back, the internal schema tables do
# not reset.
#
ifcapable tempdb {
for {set i 1} {$i<50} {incr i 5} {
do_test interrupt-3.$i.1 {
execsql {
BEGIN;
CREATE TEMP TABLE t2(x,y);
SELECT name FROM sqlite_temp_master;
}
} {t2}
do_test interrupt-3.$i.2 {
set ::sqlite_interrupt_count $::i
catchsql {
INSERT INTO t2 SELECT * FROM t1;
}
} {1 interrupted}
do_test interrupt-3.$i.3 {
execsql {
SELECT name FROM sqlite_temp_master;
}
} {t2}
do_test interrupt-3.$i.4 {
catchsql {
ROLLBACK
}
} {0 {}}
do_test interrupt-3.$i.5 {
catchsql {SELECT name FROM sqlite_temp_master};
execsql {
SELECT name FROM sqlite_temp_master;
}
} {}
}
}
# There are reports of a memory leak if an interrupt occurs during
# the beginning of a complex query - before the first callback. We
# will try to reproduce it here:
#
execsql {
CREATE TABLE t2(a,b,c);
INSERT INTO t2 SELECT round(a/10), randstr(50,80), randstr(50,60) FROM t1;
}
set sql {
SELECT max(min(b,c)), min(max(b,c)), a FROM t2 GROUP BY a ORDER BY a;
}
set sqlite_interrupt_count 1000000
execsql $sql
set max_count [expr {1000000-$sqlite_interrupt_count}]
for {set i 1} {$i<$max_count-5} {incr i 1} {
do_test interrupt-4.$i.1 {
set ::sqlite_interrupt_count $::i
catchsql $sql
} {1 interrupted}
}
# Interrupt during parsing
#
do_test interrupt-5.1 {
proc fake_interrupt {args} {sqlite3_interrupt $::DB; return SQLITE_OK}
db collation_needed fake_interrupt
catchsql {
CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);
}
} {1 interrupt}
do_test interrupt-5.2 {
proc fake_interrupt {args} {db interrupt; return SQLITE_OK}
db collation_needed fake_interrupt
catchsql {
CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);
}
} {1 interrupt}
finish_test
+605
View File
@@ -0,0 +1,605 @@
# 2001 September 15
#
# 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 regression tests for SQLite library.
#
# This file implements tests for the special processing associated
# with INTEGER PRIMARY KEY columns.
#
# $Id: intpkey.test,v 1.23 2005/07/21 03:48:20 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create a table with a primary key and a datatype other than
# integer
#
do_test intpkey-1.0 {
execsql {
CREATE TABLE t1(a TEXT PRIMARY KEY, b, c);
}
} {}
# There should be an index associated with the primary key
#
do_test intpkey-1.1 {
execsql {
SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='t1';
}
} {sqlite_autoindex_t1_1}
# Now create a table with an integer primary key and verify that
# there is no associated index.
#
do_test intpkey-1.2 {
execsql {
DROP TABLE t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='t1';
}
} {}
# Insert some records into the new table. Specify the primary key
# and verify that the key is used as the record number.
#
do_test intpkey-1.3 {
execsql {
INSERT INTO t1 VALUES(5,'hello','world');
}
db last_insert_rowid
} {5}
do_test intpkey-1.4 {
execsql {
SELECT * FROM t1;
}
} {5 hello world}
do_test intpkey-1.5 {
execsql {
SELECT rowid, * FROM t1;
}
} {5 5 hello world}
# Attempting to insert a duplicate primary key should give a constraint
# failure.
#
do_test intpkey-1.6 {
set r [catch {execsql {
INSERT INTO t1 VALUES(5,'second','entry');
}} msg]
lappend r $msg
} {1 {PRIMARY KEY must be unique}}
do_test intpkey-1.7 {
execsql {
SELECT rowid, * FROM t1;
}
} {5 5 hello world}
do_test intpkey-1.8 {
set r [catch {execsql {
INSERT INTO t1 VALUES(6,'second','entry');
}} msg]
lappend r $msg
} {0 {}}
do_test intpkey-1.8.1 {
db last_insert_rowid
} {6}
do_test intpkey-1.9 {
execsql {
SELECT rowid, * FROM t1;
}
} {5 5 hello world 6 6 second entry}
# A ROWID is automatically generated for new records that do not specify
# the integer primary key.
#
do_test intpkey-1.10 {
execsql {
INSERT INTO t1(b,c) VALUES('one','two');
SELECT b FROM t1 ORDER BY b;
}
} {hello one second}
# Try to change the ROWID for the new entry.
#
do_test intpkey-1.11 {
execsql {
UPDATE t1 SET a=4 WHERE b='one';
SELECT * FROM t1;
}
} {4 one two 5 hello world 6 second entry}
# Make sure SELECT statements are able to use the primary key column
# as an index.
#
do_test intpkey-1.12.1 {
execsql {
SELECT * FROM t1 WHERE a==4;
}
} {4 one two}
do_test intpkey-1.12.2 {
set sqlite_query_plan
} {t1 *}
# Try to insert a non-integer value into the primary key field. This
# should result in a data type mismatch.
#
do_test intpkey-1.13.1 {
set r [catch {execsql {
INSERT INTO t1 VALUES('x','y','z');
}} msg]
lappend r $msg
} {1 {datatype mismatch}}
do_test intpkey-1.13.2 {
set r [catch {execsql {
INSERT INTO t1 VALUES('','y','z');
}} msg]
lappend r $msg
} {1 {datatype mismatch}}
do_test intpkey-1.14 {
set r [catch {execsql {
INSERT INTO t1 VALUES(3.4,'y','z');
}} msg]
lappend r $msg
} {1 {datatype mismatch}}
do_test intpkey-1.15 {
set r [catch {execsql {
INSERT INTO t1 VALUES(-3,'y','z');
}} msg]
lappend r $msg
} {0 {}}
do_test intpkey-1.16 {
execsql {SELECT * FROM t1}
} {-3 y z 4 one two 5 hello world 6 second entry}
#### INDICES
# Check to make sure indices work correctly with integer primary keys
#
do_test intpkey-2.1 {
execsql {
CREATE INDEX i1 ON t1(b);
SELECT * FROM t1 WHERE b=='y'
}
} {-3 y z}
do_test intpkey-2.1.1 {
execsql {
SELECT * FROM t1 WHERE b=='y' AND rowid<0
}
} {-3 y z}
do_test intpkey-2.1.2 {
execsql {
SELECT * FROM t1 WHERE b=='y' AND rowid<0 AND rowid>=-20
}
} {-3 y z}
do_test intpkey-2.1.3 {
execsql {
SELECT * FROM t1 WHERE b>='y'
}
} {-3 y z}
do_test intpkey-2.1.4 {
execsql {
SELECT * FROM t1 WHERE b>='y' AND rowid<10
}
} {-3 y z}
do_test intpkey-2.2 {
execsql {
UPDATE t1 SET a=8 WHERE b=='y';
SELECT * FROM t1 WHERE b=='y';
}
} {8 y z}
do_test intpkey-2.3 {
execsql {
SELECT rowid, * FROM t1;
}
} {4 4 one two 5 5 hello world 6 6 second entry 8 8 y z}
do_test intpkey-2.4 {
execsql {
SELECT rowid, * FROM t1 WHERE b<'second'
}
} {5 5 hello world 4 4 one two}
do_test intpkey-2.4.1 {
execsql {
SELECT rowid, * FROM t1 WHERE 'second'>b
}
} {5 5 hello world 4 4 one two}
do_test intpkey-2.4.2 {
execsql {
SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b
}
} {4 4 one two 5 5 hello world}
do_test intpkey-2.4.3 {
execsql {
SELECT rowid, * FROM t1 WHERE 8>rowid AND 'second'>b AND 0<rowid
}
} {4 4 one two 5 5 hello world}
do_test intpkey-2.5 {
execsql {
SELECT rowid, * FROM t1 WHERE b>'a'
}
} {5 5 hello world 4 4 one two 6 6 second entry 8 8 y z}
do_test intpkey-2.6 {
execsql {
DELETE FROM t1 WHERE rowid=4;
SELECT * FROM t1 WHERE b>'a';
}
} {5 hello world 6 second entry 8 y z}
do_test intpkey-2.7 {
execsql {
UPDATE t1 SET a=-4 WHERE rowid=8;
SELECT * FROM t1 WHERE b>'a';
}
} {5 hello world 6 second entry -4 y z}
do_test intpkey-2.7 {
execsql {
SELECT * FROM t1
}
} {-4 y z 5 hello world 6 second entry}
# Do an SQL statement. Append the search count to the end of the result.
#
proc count sql {
set ::sqlite_search_count 0
return [concat [execsql $sql] $::sqlite_search_count]
}
# Create indices that include the integer primary key as one of their
# columns.
#
do_test intpkey-3.1 {
execsql {
CREATE INDEX i2 ON t1(a);
}
} {}
do_test intpkey-3.2 {
count {
SELECT * FROM t1 WHERE a=5;
}
} {5 hello world 0}
do_test intpkey-3.3 {
count {
SELECT * FROM t1 WHERE a>4 AND a<6;
}
} {5 hello world 2}
do_test intpkey-3.4 {
count {
SELECT * FROM t1 WHERE b>='hello' AND b<'hello2';
}
} {5 hello world 3}
do_test intpkey-3.5 {
execsql {
CREATE INDEX i3 ON t1(c,a);
}
} {}
do_test intpkey-3.6 {
count {
SELECT * FROM t1 WHERE c=='world';
}
} {5 hello world 3}
do_test intpkey-3.7 {
execsql {INSERT INTO t1 VALUES(11,'hello','world')}
count {
SELECT * FROM t1 WHERE c=='world';
}
} {5 hello world 11 hello world 5}
do_test intpkey-3.8 {
count {
SELECT * FROM t1 WHERE c=='world' AND a>7;
}
} {11 hello world 5}
do_test intpkey-3.9 {
count {
SELECT * FROM t1 WHERE 7<a;
}
} {11 hello world 1}
# Test inequality constraints on integer primary keys and rowids
#
do_test intpkey-4.1 {
count {
SELECT * FROM t1 WHERE 11=rowid
}
} {11 hello world 0}
do_test intpkey-4.2 {
count {
SELECT * FROM t1 WHERE 11=rowid AND b=='hello'
}
} {11 hello world 0}
do_test intpkey-4.3 {
count {
SELECT * FROM t1 WHERE 11=rowid AND b=='hello' AND c IS NOT NULL;
}
} {11 hello world 0}
do_test intpkey-4.4 {
count {
SELECT * FROM t1 WHERE rowid==11
}
} {11 hello world 0}
do_test intpkey-4.5 {
count {
SELECT * FROM t1 WHERE oid==11 AND b=='hello'
}
} {11 hello world 0}
do_test intpkey-4.6 {
count {
SELECT * FROM t1 WHERE a==11 AND b=='hello' AND c IS NOT NULL;
}
} {11 hello world 0}
do_test intpkey-4.7 {
count {
SELECT * FROM t1 WHERE 8<rowid;
}
} {11 hello world 1}
do_test intpkey-4.8 {
count {
SELECT * FROM t1 WHERE 8<rowid AND 11>=oid;
}
} {11 hello world 1}
do_test intpkey-4.9 {
count {
SELECT * FROM t1 WHERE 11<=_rowid_ AND 12>=a;
}
} {11 hello world 1}
do_test intpkey-4.10 {
count {
SELECT * FROM t1 WHERE 0>=_rowid_;
}
} {-4 y z 1}
do_test intpkey-4.11 {
count {
SELECT * FROM t1 WHERE a<0;
}
} {-4 y z 1}
do_test intpkey-4.12 {
count {
SELECT * FROM t1 WHERE a<0 AND a>10;
}
} {1}
# Make sure it is OK to insert a rowid of 0
#
do_test intpkey-5.1 {
execsql {
INSERT INTO t1 VALUES(0,'zero','entry');
}
count {
SELECT * FROM t1 WHERE a=0;
}
} {0 zero entry 0}
do_test intpkey-5.2 {
execsql {
SELECT rowid, a FROM t1
}
} {-4 -4 0 0 5 5 6 6 11 11}
# Test the ability of the COPY command to put data into a
# table that contains an integer primary key.
#
# COPY command has been removed. But we retain these tests so
# that the tables will contain the right data for tests that follow.
#
do_test intpkey-6.1 {
execsql {
BEGIN;
INSERT INTO t1 VALUES(20,'b-20','c-20');
INSERT INTO t1 VALUES(21,'b-21','c-21');
INSERT INTO t1 VALUES(22,'b-22','c-22');
COMMIT;
SELECT * FROM t1 WHERE a>=20;
}
} {20 b-20 c-20 21 b-21 c-21 22 b-22 c-22}
do_test intpkey-6.2 {
execsql {
SELECT * FROM t1 WHERE b=='hello'
}
} {5 hello world 11 hello world}
do_test intpkey-6.3 {
execsql {
DELETE FROM t1 WHERE b='b-21';
SELECT * FROM t1 WHERE b=='b-21';
}
} {}
do_test intpkey-6.4 {
execsql {
SELECT * FROM t1 WHERE a>=20
}
} {20 b-20 c-20 22 b-22 c-22}
# Do an insert of values with the columns specified out of order.
#
do_test intpkey-7.1 {
execsql {
INSERT INTO t1(c,b,a) VALUES('row','new',30);
SELECT * FROM t1 WHERE rowid>=30;
}
} {30 new row}
do_test intpkey-7.2 {
execsql {
SELECT * FROM t1 WHERE rowid>20;
}
} {22 b-22 c-22 30 new row}
# Do an insert from a select statement.
#
do_test intpkey-8.1 {
execsql {
CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z);
INSERT INTO t2 SELECT * FROM t1;
SELECT rowid FROM t2;
}
} {-4 0 5 6 11 20 22 30}
do_test intpkey-8.2 {
execsql {
SELECT x FROM t2;
}
} {-4 0 5 6 11 20 22 30}
do_test intpkey-9.1 {
execsql {
UPDATE t1 SET c='www' WHERE c='world';
SELECT rowid, a, c FROM t1 WHERE c=='www';
}
} {5 5 www 11 11 www}
# Check insert of NULL for primary key
#
do_test intpkey-10.1 {
execsql {
DROP TABLE t2;
CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z);
INSERT INTO t2 VALUES(NULL, 1, 2);
SELECT * from t2;
}
} {1 1 2}
do_test intpkey-10.2 {
execsql {
INSERT INTO t2 VALUES(NULL, 2, 3);
SELECT * from t2 WHERE x=2;
}
} {2 2 3}
do_test intpkey-10.3 {
execsql {
INSERT INTO t2 SELECT NULL, z, y FROM t2;
SELECT * FROM t2;
}
} {1 1 2 2 2 3 3 2 1 4 3 2}
# This tests checks to see if a floating point number can be used
# to reference an integer primary key.
#
do_test intpkey-11.1 {
execsql {
SELECT b FROM t1 WHERE a=2.0+3.0;
}
} {hello}
do_test intpkey-11.1 {
execsql {
SELECT b FROM t1 WHERE a=2.0+3.5;
}
} {}
integrity_check intpkey-12.1
# Try to use a string that looks like a floating point number as
# an integer primary key. This should actually work when the floating
# point value can be rounded to an integer without loss of data.
#
do_test intpkey-13.1 {
execsql {
SELECT * FROM t1 WHERE a=1;
}
} {}
do_test intpkey-13.2 {
execsql {
INSERT INTO t1 VALUES('1.0',2,3);
SELECT * FROM t1 WHERE a=1;
}
} {1 2 3}
do_test intpkey-13.3 {
catchsql {
INSERT INTO t1 VALUES('1.5',3,4);
}
} {1 {datatype mismatch}}
ifcapable {bloblit} {
do_test intpkey-13.4 {
catchsql {
INSERT INTO t1 VALUES(x'123456',3,4);
}
} {1 {datatype mismatch}}
}
do_test intpkey-13.5 {
catchsql {
INSERT INTO t1 VALUES('+1234567890',3,4);
}
} {0 {}}
# Compare an INTEGER PRIMARY KEY against a TEXT expression. The INTEGER
# affinity should be applied to the text value before the comparison
# takes place.
#
do_test intpkey-14.1 {
execsql {
CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT);
INSERT INTO t3 VALUES(1, 1, 'one');
INSERT INTO t3 VALUES(2, 2, '2');
INSERT INTO t3 VALUES(3, 3, 3);
}
} {}
do_test intpkey-14.2 {
execsql {
SELECT * FROM t3 WHERE a>2;
}
} {3 3 3}
do_test intpkey-14.3 {
execsql {
SELECT * FROM t3 WHERE a>'2';
}
} {3 3 3}
do_test intpkey-14.4 {
execsql {
SELECT * FROM t3 WHERE a<'2';
}
} {1 1 one}
do_test intpkey-14.5 {
execsql {
SELECT * FROM t3 WHERE a<c;
}
} {1 1 one}
do_test intpkey-14.6 {
execsql {
SELECT * FROM t3 WHERE a=c;
}
} {2 2 2 3 3 3}
# Check for proper handling of primary keys greater than 2^31.
# Ticket #1188
#
do_test intpkey-15.1 {
execsql {
INSERT INTO t1 VALUES(2147483647, 'big-1', 123);
SELECT * FROM t1 WHERE a>2147483648;
}
} {}
do_test intpkey-15.2 {
execsql {
INSERT INTO t1 VALUES(NULL, 'big-2', 234);
SELECT b FROM t1 WHERE a>=2147483648;
}
} {big-2}
do_test intpkey-15.3 {
execsql {
SELECT b FROM t1 WHERE a>2147483648;
}
} {}
do_test intpkey-15.4 {
execsql {
SELECT b FROM t1 WHERE a>=2147483647;
}
} {big-1 big-2}
do_test intpkey-15.5 {
execsql {
SELECT b FROM t1 WHERE a<2147483648;
}
} {y zero 2 hello second hello b-20 b-22 new 3 big-1}
do_test intpkey-15.6 {
execsql {
SELECT b FROM t1 WHERE a<12345678901;
}
} {y zero 2 hello second hello b-20 b-22 new 3 big-1 big-2}
do_test intpkey-15.7 {
execsql {
SELECT b FROM t1 WHERE a>12345678901;
}
} {}
finish_test
+259
View File
@@ -0,0 +1,259 @@
# 2001 October 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
#
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: ioerr.test,v 1.27 2006/09/15 07:28:51 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error
# on the 8th IO operation in the SQL script below doesn't report an error.
#
# This is because the 8th IO call attempts to read page 2 of the database
# file when the file on disk is only 1 page. The pager layer detects that
# this has happened and suppresses the error returned by the OS layer.
#
do_ioerr_test ioerr-1 -erc 1 -sqlprep {
SELECT * FROM sqlite_master;
} -sqlbody {
CREATE TABLE t1(a,b,c);
SELECT * FROM sqlite_master;
BEGIN TRANSACTION;
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(4,5,6);
ROLLBACK;
SELECT * FROM t1;
BEGIN TRANSACTION;
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(4,5,6);
COMMIT;
SELECT * FROM t1;
DELETE FROM t1 WHERE a<100;
} -exclude [expr [string match [execsql {pragma auto_vacuum}] 1] ? 4 : 0]
# Test for IO errors during a VACUUM.
#
# The first IO call is excluded from the test. This call attempts to read
# the file-header of the temporary database used by VACUUM. Since the
# database doesn't exist at that point, the IO error is not detected.
#
# Additionally, if auto-vacuum is enabled, the 12th IO error is not
# detected. Same reason as the 8th in the test case above.
#
ifcapable vacuum {
do_ioerr_test ioerr-2 -cksum true -sqlprep {
BEGIN;
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES(1, randstr(50,50), randstr(50,50));
INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 SELECT a+8, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 SELECT a+16, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 SELECT a+32, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 SELECT a+64, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 SELECT a+128, b||'-'||rowid, c||'-'||rowid FROM t1;
INSERT INTO t1 VALUES(1, randstr(600,600), randstr(600,600));
CREATE TABLE t2 AS SELECT * FROM t1;
CREATE TABLE t3 AS SELECT * FROM t1;
COMMIT;
DROP TABLE t2;
} -sqlbody {
VACUUM;
} -exclude [list \
1 [expr [string match [execsql {pragma auto_vacuum}] 1]?9:-1]]
}
do_ioerr_test ioerr-3 -tclprep {
execsql {
PRAGMA cache_size = 10;
BEGIN;
CREATE TABLE abc(a);
INSERT INTO abc VALUES(randstr(1500,1500)); -- Page 4 is overflow
}
for {set i 0} {$i<150} {incr i} {
execsql {
INSERT INTO abc VALUES(randstr(100,100));
}
}
execsql COMMIT
} -sqlbody {
CREATE TABLE abc2(a);
BEGIN;
DELETE FROM abc WHERE length(a)>100;
UPDATE abc SET a = randstr(90,90);
COMMIT;
CREATE TABLE abc3(a);
}
# Test IO errors that can occur retrieving a record header that flows over
# onto an overflow page.
do_ioerr_test ioerr-4 -tclprep {
set sql "CREATE TABLE abc(a1"
for {set i 2} {$i<1300} {incr i} {
append sql ", a$i"
}
append sql ");"
execsql $sql
execsql {INSERT INTO abc (a1) VALUES(NULL)}
} -sqlbody {
SELECT * FROM abc;
}
# Test IO errors that may occur during a multi-file commit.
#
# Tests 8 and 17 are excluded when auto-vacuum is enabled for the same
# reason as in test cases ioerr-1.XXX
set ex ""
if {[string match [execsql {pragma auto_vacuum}] 1]} {
set ex [list 4 17]
}
do_ioerr_test ioerr-5 -sqlprep {
ATTACH 'test2.db' AS test2;
} -sqlbody {
BEGIN;
CREATE TABLE t1(a,b,c);
CREATE TABLE test2.t2(a,b,c);
COMMIT;
} -exclude $ex
# Test IO errors when replaying two hot journals from a 2-file
# transaction. This test only runs on UNIX.
ifcapable crashtest {
if {![catch {sqlite3 -has_codec} r] && !$r} {
do_ioerr_test ioerr-6 -tclprep {
execsql {
ATTACH 'test2.db' as aux;
CREATE TABLE tx(a, b);
CREATE TABLE aux.ty(a, b);
}
set rc [crashsql 2 test2.db-journal {
ATTACH 'test2.db' as aux;
PRAGMA cache_size = 10;
BEGIN;
CREATE TABLE aux.t2(a, b, c);
CREATE TABLE t1(a, b, c);
COMMIT;
}]
if {$rc!="1 {child process exited abnormally}"} {
error "Wrong error message: $rc"
}
} -sqlbody {
SELECT * FROM sqlite_master;
SELECT * FROM aux.sqlite_master;
}
}
}
# Test handling of IO errors that occur while rolling back hot journal
# files.
#
# These tests can't be run on windows because the windows version of
# SQLite holds a mandatory exclusive lock on journal files it has open.
#
if {$tcl_platform(platform)!="windows"} {
do_ioerr_test ioerr-7 -tclprep {
db close
sqlite3 db2 test2.db
db2 eval {
PRAGMA synchronous = 0;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
BEGIN;
INSERT INTO t1 VALUES(3, 4);
}
copy_file test2.db test.db
copy_file test2.db-journal test.db-journal
db2 close
} -tclbody {
sqlite3 db test.db
db eval {
SELECT * FROM t1;
}
} -exclude 1
}
# For test coverage: Cause an I/O failure while trying to read a
# short field (one that fits into a Mem buffer without mallocing
# for space).
#
do_ioerr_test ioerr-8 -tclprep {
execsql {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
}
db close
sqlite3 db test.db
} -sqlbody {
SELECT c FROM t1;
}
# For test coverage: Cause an IO error whilst reading the master-journal
# name from a journal file.
if {$tcl_platform(platform)=="unix"} {
do_ioerr_test ioerr-9 -tclprep {
execsql {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
BEGIN;
INSERT INTO t1 VALUES(randstr(200,200), randstr(1000,1000), 2);
}
copy_file test.db-journal test2.db-journal
execsql {
COMMIT;
}
copy_file test2.db-journal test.db-journal
set f [open test.db-journal a]
fconfigure $f -encoding binary
puts -nonewline $f "hello"
puts -nonewline $f "\x00\x00\x00\x05\x01\x02\x03\x04"
puts -nonewline $f "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7"
close $f
} -sqlbody {
SELECT a FROM t1;
}
}
# For test coverage: Cause an IO error during statement playback (i.e.
# a constraint).
do_ioerr_test ioerr-10 -tclprep {
execsql {
BEGIN;
CREATE TABLE t1(a PRIMARY KEY, b);
}
for {set i 0} {$i < 500} {incr i} {
execsql {INSERT INTO t1 VALUES(:i, 'hello world');}
}
execsql {
COMMIT;
}
} -tclbody {
catch {execsql {
BEGIN;
INSERT INTO t1 VALUES('abc', 123);
INSERT INTO t1 VALUES('def', 123);
INSERT INTO t1 VALUES('ghi', 123);
INSERT INTO t1 SELECT (a+500)%900, 'good string' FROM t1;
}} msg
if {$msg != "column a is not unique"} {
error $msg
}
}
finish_test
+461
View File
@@ -0,0 +1,461 @@
# 2002 May 24
#
# 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 regression tests for SQLite library.
#
# This file implements tests for joins, including outer joins.
#
# $Id: join.test,v 1.22 2006/06/20 11:01:09 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test join-1.1 {
execsql {
CREATE TABLE t1(a,b,c);
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t1 VALUES(2,3,4);
INSERT INTO t1 VALUES(3,4,5);
SELECT * FROM t1;
}
} {1 2 3 2 3 4 3 4 5}
do_test join-1.2 {
execsql {
CREATE TABLE t2(b,c,d);
INSERT INTO t2 VALUES(1,2,3);
INSERT INTO t2 VALUES(2,3,4);
INSERT INTO t2 VALUES(3,4,5);
SELECT * FROM t2;
}
} {1 2 3 2 3 4 3 4 5}
do_test join-1.3 {
execsql2 {
SELECT * FROM t1 NATURAL JOIN t2;
}
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5}
do_test join-1.3.1 {
execsql2 {
SELECT * FROM t2 NATURAL JOIN t1;
}
} {b 2 c 3 d 4 a 1 b 3 c 4 d 5 a 2}
do_test join-1.3.2 {
execsql2 {
SELECT * FROM t2 AS x NATURAL JOIN t1;
}
} {b 2 c 3 d 4 a 1 b 3 c 4 d 5 a 2}
do_test join-1.3.3 {
execsql2 {
SELECT * FROM t2 NATURAL JOIN t1 AS y;
}
} {b 2 c 3 d 4 a 1 b 3 c 4 d 5 a 2}
do_test join-1.3.4 {
execsql {
SELECT b FROM t1 NATURAL JOIN t2;
}
} {2 3}
do_test join-1.4.1 {
execsql2 {
SELECT * FROM t1 INNER JOIN t2 USING(b,c);
}
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5}
do_test join-1.4.2 {
execsql2 {
SELECT * FROM t1 AS x INNER JOIN t2 USING(b,c);
}
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5}
do_test join-1.4.3 {
execsql2 {
SELECT * FROM t1 INNER JOIN t2 AS y USING(b,c);
}
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5}
do_test join-1.4.4 {
execsql2 {
SELECT * FROM t1 AS x INNER JOIN t2 AS y USING(b,c);
}
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5}
do_test join-1.4.5 {
execsql {
SELECT b FROM t1 JOIN t2 USING(b);
}
} {2 3}
do_test join-1.5 {
execsql2 {
SELECT * FROM t1 INNER JOIN t2 USING(b);
}
} {a 1 b 2 c 3 c 3 d 4 a 2 b 3 c 4 c 4 d 5}
do_test join-1.6 {
execsql2 {
SELECT * FROM t1 INNER JOIN t2 USING(c);
}
} {a 1 b 2 c 3 b 2 d 4 a 2 b 3 c 4 b 3 d 5}
do_test join-1.7 {
execsql2 {
SELECT * FROM t1 INNER JOIN t2 USING(c,b);
}
} {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5}
do_test join-1.8 {
execsql {
SELECT * FROM t1 NATURAL CROSS JOIN t2;
}
} {1 2 3 4 2 3 4 5}
do_test join-1.9 {
execsql {
SELECT * FROM t1 CROSS JOIN t2 USING(b,c);
}
} {1 2 3 4 2 3 4 5}
do_test join-1.10 {
execsql {
SELECT * FROM t1 NATURAL INNER JOIN t2;
}
} {1 2 3 4 2 3 4 5}
do_test join-1.11 {
execsql {
SELECT * FROM t1 INNER JOIN t2 USING(b,c);
}
} {1 2 3 4 2 3 4 5}
do_test join-1.12 {
execsql {
SELECT * FROM t1 natural inner join t2;
}
} {1 2 3 4 2 3 4 5}
ifcapable subquery {
do_test join-1.13 {
execsql2 {
SELECT * FROM t1 NATURAL JOIN
(SELECT b as 'c', c as 'd', d as 'e' FROM t2) as t3
}
} {a 1 b 2 c 3 d 4 e 5}
do_test join-1.14 {
execsql2 {
SELECT * FROM (SELECT b as 'c', c as 'd', d as 'e' FROM t2) as 'tx'
NATURAL JOIN t1
}
} {c 3 d 4 e 5 a 1 b 2}
}
do_test join-1.15 {
execsql {
CREATE TABLE t3(c,d,e);
INSERT INTO t3 VALUES(2,3,4);
INSERT INTO t3 VALUES(3,4,5);
INSERT INTO t3 VALUES(4,5,6);
SELECT * FROM t3;
}
} {2 3 4 3 4 5 4 5 6}
do_test join-1.16 {
execsql {
SELECT * FROM t1 natural join t2 natural join t3;
}
} {1 2 3 4 5 2 3 4 5 6}
do_test join-1.17 {
execsql2 {
SELECT * FROM t1 natural join t2 natural join t3;
}
} {a 1 b 2 c 3 d 4 e 5 a 2 b 3 c 4 d 5 e 6}
do_test join-1.18 {
execsql {
CREATE TABLE t4(d,e,f);
INSERT INTO t4 VALUES(2,3,4);
INSERT INTO t4 VALUES(3,4,5);
INSERT INTO t4 VALUES(4,5,6);
SELECT * FROM t4;
}
} {2 3 4 3 4 5 4 5 6}
do_test join-1.19.1 {
execsql {
SELECT * FROM t1 natural join t2 natural join t4;
}
} {1 2 3 4 5 6}
do_test join-1.19.2 {
execsql2 {
SELECT * FROM t1 natural join t2 natural join t4;
}
} {a 1 b 2 c 3 d 4 e 5 f 6}
do_test join-1.20 {
execsql {
SELECT * FROM t1 natural join t2 natural join t3 WHERE t1.a=1
}
} {1 2 3 4 5}
do_test join-2.1 {
execsql {
SELECT * FROM t1 NATURAL LEFT JOIN t2;
}
} {1 2 3 4 2 3 4 5 3 4 5 {}}
do_test join-2.2 {
execsql {
SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1;
}
} {1 2 3 {} 2 3 4 1 3 4 5 2}
do_test join-2.3 {
catchsql {
SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2;
}
} {1 {RIGHT and FULL OUTER JOINs are not currently supported}}
do_test join-2.4 {
execsql {
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d
}
} {1 2 3 {} {} {} 2 3 4 {} {} {} 3 4 5 1 2 3}
do_test join-2.5 {
execsql {
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d WHERE t1.a>1
}
} {2 3 4 {} {} {} 3 4 5 1 2 3}
do_test join-2.6 {
execsql {
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d WHERE t2.b IS NULL OR t2.b>1
}
} {1 2 3 {} {} {} 2 3 4 {} {} {}}
do_test join-3.1 {
catchsql {
SELECT * FROM t1 NATURAL JOIN t2 ON t1.a=t2.b;
}
} {1 {a NATURAL join may not have an ON or USING clause}}
do_test join-3.2 {
catchsql {
SELECT * FROM t1 NATURAL JOIN t2 USING(b);
}
} {1 {a NATURAL join may not have an ON or USING clause}}
do_test join-3.3 {
catchsql {
SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b);
}
} {1 {cannot have both ON and USING clauses in the same join}}
do_test join-3.4 {
catchsql {
SELECT * FROM t1 JOIN t2 USING(a);
}
} {1 {cannot join using column a - column not present in both tables}}
do_test join-3.5 {
catchsql {
SELECT * FROM t1 USING(a);
}
} {0 {1 2 3 2 3 4 3 4 5}}
do_test join-3.6 {
catchsql {
SELECT * FROM t1 JOIN t2 ON t3.a=t2.b;
}
} {1 {no such column: t3.a}}
do_test join-3.7 {
catchsql {
SELECT * FROM t1 INNER OUTER JOIN t2;
}
} {1 {unknown or unsupported join type: INNER OUTER}}
do_test join-3.7 {
catchsql {
SELECT * FROM t1 LEFT BOGUS JOIN t2;
}
} {1 {unknown or unsupported join type: LEFT BOGUS}}
do_test join-4.1 {
execsql {
BEGIN;
CREATE TABLE t5(a INTEGER PRIMARY KEY);
CREATE TABLE t6(a INTEGER);
INSERT INTO t6 VALUES(NULL);
INSERT INTO t6 VALUES(NULL);
INSERT INTO t6 SELECT * FROM t6;
INSERT INTO t6 SELECT * FROM t6;
INSERT INTO t6 SELECT * FROM t6;
INSERT INTO t6 SELECT * FROM t6;
INSERT INTO t6 SELECT * FROM t6;
INSERT INTO t6 SELECT * FROM t6;
COMMIT;
}
execsql {
SELECT * FROM t6 NATURAL JOIN t5;
}
} {}
do_test join-4.2 {
execsql {
SELECT * FROM t6, t5 WHERE t6.a<t5.a;
}
} {}
do_test join-4.3 {
execsql {
SELECT * FROM t6, t5 WHERE t6.a>t5.a;
}
} {}
do_test join-4.4 {
execsql {
UPDATE t6 SET a='xyz';
SELECT * FROM t6 NATURAL JOIN t5;
}
} {}
do_test join-4.6 {
execsql {
SELECT * FROM t6, t5 WHERE t6.a<t5.a;
}
} {}
do_test join-4.7 {
execsql {
SELECT * FROM t6, t5 WHERE t6.a>t5.a;
}
} {}
do_test join-4.8 {
execsql {
UPDATE t6 SET a=1;
SELECT * FROM t6 NATURAL JOIN t5;
}
} {}
do_test join-4.9 {
execsql {
SELECT * FROM t6, t5 WHERE t6.a<t5.a;
}
} {}
do_test join-4.10 {
execsql {
SELECT * FROM t6, t5 WHERE t6.a>t5.a;
}
} {}
do_test join-5.1 {
execsql {
BEGIN;
create table centros (id integer primary key, centro);
INSERT INTO centros VALUES(1,'xxx');
create table usuarios (id integer primary key, nombre, apellidos,
idcentro integer);
INSERT INTO usuarios VALUES(1,'a','aa',1);
INSERT INTO usuarios VALUES(2,'b','bb',1);
INSERT INTO usuarios VALUES(3,'c','cc',NULL);
create index idcentro on usuarios (idcentro);
END;
select usuarios.id, usuarios.nombre, centros.centro from
usuarios left outer join centros on usuarios.idcentro = centros.id;
}
} {1 a xxx 2 b xxx 3 c {}}
# A test for ticket #247.
#
do_test join-7.1 {
execsql {
CREATE TABLE t7 (x, y);
INSERT INTO t7 VALUES ("pa1", 1);
INSERT INTO t7 VALUES ("pa2", NULL);
INSERT INTO t7 VALUES ("pa3", NULL);
INSERT INTO t7 VALUES ("pa4", 2);
INSERT INTO t7 VALUES ("pa30", 131);
INSERT INTO t7 VALUES ("pa31", 130);
INSERT INTO t7 VALUES ("pa28", NULL);
CREATE TABLE t8 (a integer primary key, b);
INSERT INTO t8 VALUES (1, "pa1");
INSERT INTO t8 VALUES (2, "pa4");
INSERT INTO t8 VALUES (3, NULL);
INSERT INTO t8 VALUES (4, NULL);
INSERT INTO t8 VALUES (130, "pa31");
INSERT INTO t8 VALUES (131, "pa30");
SELECT coalesce(t8.a,999) from t7 LEFT JOIN t8 on y=a;
}
} {1 999 999 2 131 130 999}
# Make sure a left join where the right table is really a view that
# is itself a join works right. Ticket #306.
#
ifcapable view {
do_test join-8.1 {
execsql {
BEGIN;
CREATE TABLE t9(a INTEGER PRIMARY KEY, b);
INSERT INTO t9 VALUES(1,11);
INSERT INTO t9 VALUES(2,22);
CREATE TABLE t10(x INTEGER PRIMARY KEY, y);
INSERT INTO t10 VALUES(1,2);
INSERT INTO t10 VALUES(3,3);
CREATE TABLE t11(p INTEGER PRIMARY KEY, q);
INSERT INTO t11 VALUES(2,111);
INSERT INTO t11 VALUES(3,333);
CREATE VIEW v10_11 AS SELECT x, q FROM t10, t11 WHERE t10.y=t11.p;
COMMIT;
SELECT * FROM t9 LEFT JOIN v10_11 ON( a=x );
}
} {1 11 1 111 2 22 {} {}}
ifcapable subquery {
do_test join-8.2 {
execsql {
SELECT * FROM t9 LEFT JOIN (SELECT x, q FROM t10, t11 WHERE t10.y=t11.p)
ON( a=x);
}
} {1 11 1 111 2 22 {} {}}
}
do_test join-8.3 {
execsql {
SELECT * FROM v10_11 LEFT JOIN t9 ON( a=x );
}
} {1 111 1 11 3 333 {} {}}
} ;# ifcapable view
# Ticket #350 describes a scenario where LEFT OUTER JOIN does not
# function correctly if the right table in the join is really
# subquery.
#
# To test the problem, we generate the same LEFT OUTER JOIN in two
# separate selects but with on using a subquery and the other calling
# the table directly. Then connect the two SELECTs using an EXCEPT.
# Both queries should generate the same results so the answer should
# be an empty set.
#
ifcapable compound {
do_test join-9.1 {
execsql {
BEGIN;
CREATE TABLE t12(a,b);
INSERT INTO t12 VALUES(1,11);
INSERT INTO t12 VALUES(2,22);
CREATE TABLE t13(b,c);
INSERT INTO t13 VALUES(22,222);
COMMIT;
}
} {}
ifcapable subquery {
do_test join-9.1.1 {
execsql {
SELECT * FROM t12 NATURAL LEFT JOIN t13
EXCEPT
SELECT * FROM t12 NATURAL LEFT JOIN (SELECT * FROM t13 WHERE b>0);
}
} {}
}
ifcapable view {
do_test join-9.2 {
execsql {
CREATE VIEW v13 AS SELECT * FROM t13 WHERE b>0;
SELECT * FROM t12 NATURAL LEFT JOIN t13
EXCEPT
SELECT * FROM t12 NATURAL LEFT JOIN v13;
}
} {}
} ;# ifcapable view
} ;# ifcapable compound
# Ticket #1697: Left Join WHERE clause terms that contain an
# aggregate subquery.
#
ifcapable subquery {
do_test join-10.1 {
execsql {
CREATE TABLE t21(a,b,c);
CREATE TABLE t22(p,q);
CREATE INDEX i22 ON t22(q);
SELECT a FROM t21 LEFT JOIN t22 ON b=p WHERE q=
(SELECT max(m.q) FROM t22 m JOIN t21 n ON n.b=m.p WHERE n.c=1);
}
} {}
} ;# ifcapable subquery
finish_test
+75
View File
@@ -0,0 +1,75 @@
# 2002 May 24
#
# 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 regression tests for SQLite library.
#
# This file implements tests for joins, including outer joins.
#
# $Id: join2.test,v 1.2 2005/01/21 03:12:16 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test join2-1.1 {
execsql {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,11);
INSERT INTO t1 VALUES(2,22);
INSERT INTO t1 VALUES(3,33);
SELECT * FROM t1;
}
} {1 11 2 22 3 33}
do_test join2-1.2 {
execsql {
CREATE TABLE t2(b,c);
INSERT INTO t2 VALUES(11,111);
INSERT INTO t2 VALUES(33,333);
INSERT INTO t2 VALUES(44,444);
SELECT * FROM t2;
}
} {11 111 33 333 44 444};
do_test join2-1.3 {
execsql {
CREATE TABLE t3(c,d);
INSERT INTO t3 VALUES(111,1111);
INSERT INTO t3 VALUES(444,4444);
INSERT INTO t3 VALUES(555,5555);
SELECT * FROM t3;
}
} {111 1111 444 4444 555 5555}
do_test join2-1.4 {
execsql {
SELECT * FROM
t1 NATURAL JOIN t2 NATURAL JOIN t3
}
} {1 11 111 1111}
do_test join2-1.5 {
execsql {
SELECT * FROM
t1 NATURAL JOIN t2 NATURAL LEFT OUTER JOIN t3
}
} {1 11 111 1111 3 33 333 {}}
do_test join2-1.6 {
execsql {
SELECT * FROM
t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3
}
} {1 11 111 1111}
ifcapable subquery {
do_test join2-1.7 {
execsql {
SELECT * FROM
t1 NATURAL LEFT OUTER JOIN (t2 NATURAL JOIN t3)
}
} {1 11 111 1111 2 22 {} {} 3 33 {} {}}
}
finish_test
+62
View File
@@ -0,0 +1,62 @@
# 2002 May 24
#
# 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 regression tests for SQLite library.
#
# This file implements tests for joins, including outer joins, where
# there are a large number of tables involved in the join.
#
# $Id: join3.test,v 1.4 2005/01/19 23:24:51 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# An unrestricted join
#
catch {unset ::result}
set result {}
for {set N 1} {$N<=$bitmask_size} {incr N} {
lappend result $N
do_test join3-1.$N {
execsql "CREATE TABLE t${N}(x);"
execsql "INSERT INTO t$N VALUES($N)"
set sql "SELECT * FROM t1"
for {set i 2} {$i<=$N} {incr i} {append sql ", t$i"}
execsql $sql
} $result
}
# Joins with a comparison
#
set result {}
for {set N 1} {$N<=$bitmask_size} {incr N} {
lappend result $N
do_test join3-2.$N {
set sql "SELECT * FROM t1"
for {set i 2} {$i<=$N} {incr i} {append sql ", t$i"}
set sep WHERE
for {set i 1} {$i<$N} {incr i} {
append sql " $sep t[expr {$i+1}].x==t$i.x+1"
set sep AND
}
execsql $sql
} $result
}
# Error of too many tables in the join
#
do_test join3-3.1 {
set sql "SELECT * FROM t1 AS t0, t1"
for {set i 2} {$i<=$bitmask_size} {incr i} {append sql ", t$i"}
catchsql $sql
} [list 1 "at most $bitmask_size tables in a join"]
finish_test
+98
View File
@@ -0,0 +1,98 @@
# 2002 May 24
#
# 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 regression tests for SQLite library.
#
# This file implements tests for left outer joins containing WHERE
# clauses that restrict the scope of the left term of the join.
#
# $Id: join4.test,v 1.4 2005/03/29 03:11:00 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable tempdb {
do_test join4-1.1 {
execsql {
create temp table t1(a integer, b varchar(10));
insert into t1 values(1,'one');
insert into t1 values(2,'two');
insert into t1 values(3,'three');
insert into t1 values(4,'four');
create temp table t2(x integer, y varchar(10), z varchar(10));
insert into t2 values(2,'niban','ok');
insert into t2 values(4,'yonban','err');
}
execsql {
select * from t1 left outer join t2 on t1.a=t2.x where t2.z='ok'
}
} {2 two 2 niban ok}
} else {
do_test join4-1.1 {
execsql {
create table t1(a integer, b varchar(10));
insert into t1 values(1,'one');
insert into t1 values(2,'two');
insert into t1 values(3,'three');
insert into t1 values(4,'four');
create table t2(x integer, y varchar(10), z varchar(10));
insert into t2 values(2,'niban','ok');
insert into t2 values(4,'yonban','err');
}
execsql {
select * from t1 left outer join t2 on t1.a=t2.x where t2.z='ok'
}
} {2 two 2 niban ok}
}
do_test join4-1.2 {
execsql {
select * from t1 left outer join t2 on t1.a=t2.x and t2.z='ok'
}
} {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}}
do_test join4-1.3 {
execsql {
create index i2 on t2(z);
}
execsql {
select * from t1 left outer join t2 on t1.a=t2.x where t2.z='ok'
}
} {2 two 2 niban ok}
do_test join4-1.4 {
execsql {
select * from t1 left outer join t2 on t1.a=t2.x and t2.z='ok'
}
} {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}}
do_test join4-1.5 {
execsql {
select * from t1 left outer join t2 on t1.a=t2.x where t2.z>='ok'
}
} {2 two 2 niban ok}
do_test join4-1.4 {
execsql {
select * from t1 left outer join t2 on t1.a=t2.x and t2.z>='ok'
}
} {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}}
ifcapable subquery {
do_test join4-1.6 {
execsql {
select * from t1 left outer join t2 on t1.a=t2.x where t2.z IN ('ok')
}
} {2 two 2 niban ok}
do_test join4-1.7 {
execsql {
select * from t1 left outer join t2 on t1.a=t2.x and t2.z IN ('ok')
}
} {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}}
}
finish_test
+62
View File
@@ -0,0 +1,62 @@
# 2005 September 19
#
# 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 regression tests for SQLite library.
#
# This file implements tests for left outer joins containing ON
# clauses that restrict the scope of the left term of the join.
#
# $Id: join5.test,v 1.1 2005/09/19 21:05:50 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_test join5-1.1 {
execsql {
BEGIN;
CREATE TABLE t1(a integer primary key, b integer, c integer);
CREATE TABLE t2(x integer primary key, y);
CREATE TABLE t3(p integer primary key, q);
INSERT INTO t3 VALUES(11,'t3-11');
INSERT INTO t3 VALUES(12,'t3-12');
INSERT INTO t2 VALUES(11,'t2-11');
INSERT INTO t2 VALUES(12,'t2-12');
INSERT INTO t1 VALUES(1, 5, 0);
INSERT INTO t1 VALUES(2, 11, 2);
INSERT INTO t1 VALUES(3, 12, 1);
COMMIT;
}
} {}
do_test join5-1.2 {
execsql {
select * from t1 left join t2 on t1.b=t2.x and t1.c=1
}
} {1 5 0 {} {} 2 11 2 {} {} 3 12 1 12 t2-12}
do_test join5-1.3 {
execsql {
select * from t1 left join t2 on t1.b=t2.x where t1.c=1
}
} {3 12 1 12 t2-12}
do_test join5-1.4 {
execsql {
select * from t1 left join t2 on t1.b=t2.x and t1.c=1
left join t3 on t1.b=t3.p and t1.c=2
}
} {1 5 0 {} {} {} {} 2 11 2 {} {} 11 t3-11 3 12 1 12 t2-12 {} {}}
do_test join5-1.5 {
execsql {
select * from t1 left join t2 on t1.b=t2.x and t1.c=1
left join t3 on t1.b=t3.p where t1.c=2
}
} {2 11 2 {} {} 11 t3-11}
finish_test
+67
View File
@@ -0,0 +1,67 @@
# 2005 March 15
#
# 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 regression tests for SQLite library.
#
# This file implements tests to make sure that leftover journals from
# prior databases do not try to rollback into new databases.
#
# $Id: journal1.test,v 1.2 2005/03/20 22:54:56 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# These tests will not work on windows because windows uses
# manditory file locking which breaks the file copy command.
#
if {$tcl_platform(platform)=="windows"} {
finish_test
return
}
# Create a smaple database
#
do_test journal1-1.1 {
execsql {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,randstr(10,400));
INSERT INTO t1 VALUES(2,randstr(10,400));
INSERT INTO t1 SELECT a+2, a||b FROM t1;
INSERT INTO t1 SELECT a+4, a||b FROM t1;
SELECT count(*) FROM t1;
}
} 8
# Make changes to the database and save the journal file.
# Then delete the database. Replace the the journal file
# and try to create a new database with the same name. The
# old journal should not attempt to rollback into the new
# database.
#
do_test journal1-1.2 {
execsql {
BEGIN;
DELETE FROM t1;
}
file copy -force test.db-journal test.db-journal-bu
execsql {
ROLLBACK;
}
db close
file delete test.db
file copy test.db-journal-bu test.db-journal
sqlite3 db test.db
catchsql {
SELECT * FROM sqlite_master
}
} {0 {}}
finish_test
+366
View File
@@ -0,0 +1,366 @@
# 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 to make sure that value returned by last_insert_rowid() (LIRID)
# is updated properly, especially inside triggers
#
# Note 1: insert into table is now the only statement which changes LIRID
# Note 2: upon entry into before or instead of triggers,
# LIRID is unchanged (rather than -1)
# Note 3: LIRID is changed within the context of a trigger,
# but is restored once the trigger exits
# Note 4: LIRID is not changed by an insert into a view (since everything
# is done within instead of trigger context)
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# ----------------------------------------------------------------------------
# 1.x - basic tests (no triggers)
# LIRID changed properly after an insert into a table
do_test lastinsert-1.1 {
catchsql {
create table t1 (k integer primary key);
insert into t1 values (1);
insert into t1 values (NULL);
insert into t1 values (NULL);
select last_insert_rowid();
}
} {0 3}
# LIRID unchanged after an update on a table
do_test lastinsert-1.2 {
catchsql {
update t1 set k=4 where k=2;
select last_insert_rowid();
}
} {0 3}
# LIRID unchanged after a delete from a table
do_test lastinsert-1.3 {
catchsql {
delete from t1 where k=4;
select last_insert_rowid();
}
} {0 3}
# LIRID unchanged after create table/view statements
do_test lastinsert-1.4.1 {
catchsql {
create table t2 (k integer primary key, val1, val2, val3);
select last_insert_rowid();
}
} {0 3}
ifcapable view {
do_test lastinsert-1.4.2 {
catchsql {
create view v as select * from t1;
select last_insert_rowid();
}
} {0 3}
} ;# ifcapable view
# All remaining tests involve triggers. Skip them if triggers are not
# supported in this build.
#
ifcapable {!trigger} {
finish_test
return
}
# ----------------------------------------------------------------------------
# 2.x - tests with after insert trigger
# LIRID changed properly after an insert into table containing an after trigger
do_test lastinsert-2.1 {
catchsql {
delete from t2;
create trigger r1 after insert on t1 for each row begin
insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
update t2 set k=k+10, val2=100+last_insert_rowid();
update t2 set val3=1000+last_insert_rowid();
end;
insert into t1 values (13);
select last_insert_rowid();
}
} {0 13}
# LIRID equals NEW.k upon entry into after insert trigger
do_test lastinsert-2.2 {
catchsql {
select val1 from t2;
}
} {0 13}
# LIRID changed properly by insert within context of after insert trigger
do_test lastinsert-2.3 {
catchsql {
select val2 from t2;
}
} {0 126}
# LIRID unchanged by update within context of after insert trigger
do_test lastinsert-2.4 {
catchsql {
select val3 from t2;
}
} {0 1026}
# ----------------------------------------------------------------------------
# 3.x - tests with after update trigger
# LIRID not changed after an update onto a table containing an after trigger
do_test lastinsert-3.1 {
catchsql {
delete from t2;
drop trigger r1;
create trigger r1 after update on t1 for each row begin
insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
update t2 set k=k+10, val2=100+last_insert_rowid();
update t2 set val3=1000+last_insert_rowid();
end;
update t1 set k=14 where k=3;
select last_insert_rowid();
}
} {0 13}
# LIRID unchanged upon entry into after update trigger
do_test lastinsert-3.2 {
catchsql {
select val1 from t2;
}
} {0 13}
# LIRID changed properly by insert within context of after update trigger
do_test lastinsert-3.3 {
catchsql {
select val2 from t2;
}
} {0 128}
# LIRID unchanged by update within context of after update trigger
do_test lastinsert-3.4 {
catchsql {
select val3 from t2;
}
} {0 1028}
# ----------------------------------------------------------------------------
# 4.x - tests with instead of insert trigger
# These may not be run if either views or triggers were disabled at
# compile-time
ifcapable {view && trigger} {
# LIRID not changed after an insert into view containing an instead of trigger
do_test lastinsert-4.1 {
catchsql {
delete from t2;
drop trigger r1;
create trigger r1 instead of insert on v for each row begin
insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
update t2 set k=k+10, val2=100+last_insert_rowid();
update t2 set val3=1000+last_insert_rowid();
end;
insert into v values (15);
select last_insert_rowid();
}
} {0 13}
# LIRID unchanged upon entry into instead of trigger
do_test lastinsert-4.2 {
catchsql {
select val1 from t2;
}
} {0 13}
# LIRID changed properly by insert within context of instead of trigger
do_test lastinsert-4.3 {
catchsql {
select val2 from t2;
}
} {0 130}
# LIRID unchanged by update within context of instead of trigger
do_test lastinsert-4.4 {
catchsql {
select val3 from t2;
}
} {0 1030}
} ;# ifcapable (view && trigger)
# ----------------------------------------------------------------------------
# 5.x - tests with before delete trigger
# LIRID not changed after a delete on a table containing a before trigger
do_test lastinsert-5.1 {
catchsql {
drop trigger r1; -- This was not created if views are disabled.
}
catchsql {
delete from t2;
create trigger r1 before delete on t1 for each row begin
insert into t2 values (77, last_insert_rowid(), NULL, NULL);
update t2 set k=k+10, val2=100+last_insert_rowid();
update t2 set val3=1000+last_insert_rowid();
end;
delete from t1 where k=1;
select last_insert_rowid();
}
} {0 13}
# LIRID unchanged upon entry into delete trigger
do_test lastinsert-5.2 {
catchsql {
select val1 from t2;
}
} {0 13}
# LIRID changed properly by insert within context of delete trigger
do_test lastinsert-5.3 {
catchsql {
select val2 from t2;
}
} {0 177}
# LIRID unchanged by update within context of delete trigger
do_test lastinsert-5.4 {
catchsql {
select val3 from t2;
}
} {0 1077}
# ----------------------------------------------------------------------------
# 6.x - tests with instead of update trigger
# These tests may not run if either views or triggers are disabled.
ifcapable {view && trigger} {
# LIRID not changed after an update on a view containing an instead of trigger
do_test lastinsert-6.1 {
catchsql {
delete from t2;
drop trigger r1;
create trigger r1 instead of update on v for each row begin
insert into t2 values (NEW.k*2, last_insert_rowid(), NULL, NULL);
update t2 set k=k+10, val2=100+last_insert_rowid();
update t2 set val3=1000+last_insert_rowid();
end;
update v set k=16 where k=14;
select last_insert_rowid();
}
} {0 13}
# LIRID unchanged upon entry into instead of trigger
do_test lastinsert-6.2 {
catchsql {
select val1 from t2;
}
} {0 13}
# LIRID changed properly by insert within context of instead of trigger
do_test lastinsert-6.3 {
catchsql {
select val2 from t2;
}
} {0 132}
# LIRID unchanged by update within context of instead of trigger
do_test lastinsert-6.4 {
catchsql {
select val3 from t2;
}
} {0 1032}
} ;# ifcapable (view && trigger)
# ----------------------------------------------------------------------------
# 7.x - complex tests with temporary tables and nested instead of triggers
# These do not run if views or triggers are disabled.
ifcapable {trigger && view && tempdb} {
do_test lastinsert-7.1 {
catchsql {
drop table t1; drop table t2; drop trigger r1;
create temp table t1 (k integer primary key);
create temp table t2 (k integer primary key);
create temp view v1 as select * from t1;
create temp view v2 as select * from t2;
create temp table rid (k integer primary key, rin, rout);
insert into rid values (1, NULL, NULL);
insert into rid values (2, NULL, NULL);
create temp trigger r1 instead of insert on v1 for each row begin
update rid set rin=last_insert_rowid() where k=1;
insert into t1 values (100+NEW.k);
insert into v2 values (100+last_insert_rowid());
update rid set rout=last_insert_rowid() where k=1;
end;
create temp trigger r2 instead of insert on v2 for each row begin
update rid set rin=last_insert_rowid() where k=2;
insert into t2 values (1000+NEW.k);
update rid set rout=last_insert_rowid() where k=2;
end;
insert into t1 values (77);
select last_insert_rowid();
}
} {0 77}
do_test lastinsert-7.2 {
catchsql {
insert into v1 values (5);
select last_insert_rowid();
}
} {0 77}
do_test lastinsert-7.3 {
catchsql {
select rin from rid where k=1;
}
} {0 77}
do_test lastinsert-7.4 {
catchsql {
select rout from rid where k=1;
}
} {0 105}
do_test lastinsert-7.5 {
catchsql {
select rin from rid where k=2;
}
} {0 105}
do_test lastinsert-7.6 {
catchsql {
select rout from rid where k=2;
}
} {0 1205}
do_test lastinsert-8.1 {
db close
sqlite3 db test.db
execsql {
CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
CREATE TABLE t3(a, b);
CREATE TRIGGER after_t2 AFTER INSERT ON t2 BEGIN
INSERT INTO t3 VALUES(new.x, new.y);
END;
INSERT INTO t2 VALUES(5000000000, 1);
SELECT last_insert_rowid();
}
} 5000000000
do_test lastinsert-9.1 {
db eval {INSERT INTO t2 VALUES(123456789012345,0)}
db last_insert_rowid
} {123456789012345}
} ;# ifcapable (view && trigger)
finish_test
+270
View File
@@ -0,0 +1,270 @@
# 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 to make sure that values returned by changes() and total_changes()
# are updated properly, especially inside triggers
#
# Note 1: changes() remains constant within a statement and only updates
# once the statement is finished (triggers count as part of
# statement).
# Note 2: changes() is changed within the context of a trigger much like
# last_insert_rowid() (see lastinsert.test), but is restored once
# the trigger exits.
# Note 3: changes() is not changed by a change to a view (since everything
# is done within instead of trigger context).
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# ----------------------------------------------------------------------------
# 1.x - basic tests (no triggers)
# changes() set properly after insert
do_test laststmtchanges-1.1 {
catchsql {
create table t0 (x);
insert into t0 values (1);
insert into t0 values (1);
insert into t0 values (2);
insert into t0 values (2);
insert into t0 values (1);
insert into t0 values (1);
insert into t0 values (1);
insert into t0 values (2);
select changes(), total_changes();
}
} {0 {1 8}}
# changes() set properly after update
do_test laststmtchanges-1.2 {
catchsql {
update t0 set x=3 where x=1;
select changes(), total_changes();
}
} {0 {5 13}}
# changes() unchanged within an update statement
do_test laststmtchanges-1.3 {
catchsql {
update t0 set x=x+changes() where x=3;
select count() from t0 where x=8;
}
} {0 5}
# changes() set properly after update on table where no rows changed
do_test laststmtchanges-1.4 {
catchsql {
update t0 set x=77 where x=88;
select changes();
}
} {0 0}
# changes() set properly after delete from table
do_test laststmtchanges-1.5 {
catchsql {
delete from t0 where x=2;
select changes();
}
} {0 3}
# All remaining tests involve triggers. Skip them if triggers are not
# supported in this build.
#
ifcapable {!trigger} {
finish_test
return
}
# ----------------------------------------------------------------------------
# 2.x - tests with after insert trigger
# changes() changed properly after insert into table containing after trigger
do_test laststmtchanges-2.1 {
set ::tc [db total_changes]
catchsql {
create table t1 (k integer primary key);
create table t2 (k integer primary key, v1, v2);
create trigger r1 after insert on t1 for each row begin
insert into t2 values (NULL, changes(), NULL);
update t0 set x=x;
update t2 set v2=changes();
end;
insert into t1 values (77);
select changes();
}
} {0 1}
# changes() unchanged upon entry into after insert trigger
do_test laststmtchanges-2.2 {
catchsql {
select v1 from t2;
}
} {0 3}
# changes() changed properly by update within context of after insert trigger
do_test laststmtchanges-2.3 {
catchsql {
select v2 from t2;
}
} {0 5}
# Total changes caused by firing the trigger above:
#
# 1 from "insert into t1 values(77)" +
# 1 from "insert into t2 values (NULL, changes(), NULL);" +
# 5 from "update t0 set x=x;" +
# 1 from "update t2 set v2=changes();"
#
do_test laststmtchanges-2.4 {
expr [db total_changes] - $::tc
} {8}
# ----------------------------------------------------------------------------
# 3.x - tests with after update trigger
# changes() changed properly after update into table containing after trigger
do_test laststmtchanges-3.1 {
catchsql {
drop trigger r1;
delete from t2; delete from t2;
create trigger r1 after update on t1 for each row begin
insert into t2 values (NULL, changes(), NULL);
delete from t0 where oid=1 or oid=2;
update t2 set v2=changes();
end;
update t1 set k=k;
select changes();
}
} {0 1}
# changes() unchanged upon entry into after update trigger
do_test laststmtchanges-3.2 {
catchsql {
select v1 from t2;
}
} {0 0}
# changes() changed properly by delete within context of after update trigger
do_test laststmtchanges-3.3 {
catchsql {
select v2 from t2;
}
} {0 2}
# ----------------------------------------------------------------------------
# 4.x - tests with before delete trigger
# changes() changed properly on delete from table containing before trigger
do_test laststmtchanges-4.1 {
catchsql {
drop trigger r1;
delete from t2; delete from t2;
create trigger r1 before delete on t1 for each row begin
insert into t2 values (NULL, changes(), NULL);
insert into t0 values (5);
update t2 set v2=changes();
end;
delete from t1;
select changes();
}
} {0 1}
# changes() unchanged upon entry into before delete trigger
do_test laststmtchanges-4.2 {
catchsql {
select v1 from t2;
}
} {0 0}
# changes() changed properly by insert within context of before delete trigger
do_test laststmtchanges-4.3 {
catchsql {
select v2 from t2;
}
} {0 1}
# ----------------------------------------------------------------------------
# 5.x - complex tests with temporary tables and nested instead of triggers
# These tests cannot run if the library does not have view support enabled.
ifcapable view&&tempdb {
do_test laststmtchanges-5.1 {
catchsql {
drop table t0; drop table t1; drop table t2;
create temp table t0(x);
create temp table t1 (k integer primary key);
create temp table t2 (k integer primary key);
create temp view v1 as select * from t1;
create temp view v2 as select * from t2;
create temp table n1 (k integer primary key, n);
create temp table n2 (k integer primary key, n);
insert into t0 values (1);
insert into t0 values (2);
insert into t0 values (1);
insert into t0 values (1);
insert into t0 values (1);
insert into t0 values (2);
insert into t0 values (2);
insert into t0 values (1);
create temp trigger r1 instead of insert on v1 for each row begin
insert into n1 values (NULL, changes());
update t0 set x=x*10 where x=1;
insert into n1 values (NULL, changes());
insert into t1 values (NEW.k);
insert into n1 values (NULL, changes());
update t0 set x=x*10 where x=0;
insert into v2 values (100+NEW.k);
insert into n1 values (NULL, changes());
end;
create temp trigger r2 instead of insert on v2 for each row begin
insert into n2 values (NULL, changes());
insert into t2 values (1000+NEW.k);
insert into n2 values (NULL, changes());
update t0 set x=x*100 where x=0;
insert into n2 values (NULL, changes());
delete from t0 where x=2;
insert into n2 values (NULL, changes());
end;
insert into t1 values (77);
select changes();
}
} {0 1}
do_test laststmtchanges-5.2 {
catchsql {
delete from t1 where k=88;
select changes();
}
} {0 0}
do_test laststmtchanges-5.3 {
catchsql {
insert into v1 values (5);
select changes();
}
} {0 0}
do_test laststmtchanges-5.4 {
catchsql {
select n from n1;
}
} {0 {0 5 1 0}}
do_test laststmtchanges-5.5 {
catchsql {
select n from n2;
}
} {0 {0 1 0 3}}
} ;# ifcapable view
finish_test
+386
View File
@@ -0,0 +1,386 @@
# 2005 August 13
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the LIKE and GLOB operators and
# in particular the optimizations that occur to help those operators
# run faster.
#
# $Id: like.test,v 1.5 2006/06/14 08:48:26 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create some sample data to work with.
#
do_test like-1.0 {
execsql {
CREATE TABLE t1(x TEXT);
}
foreach str {
a
ab
abc
abcd
acd
abd
bc
bcd
xyz
ABC
CDE
{ABC abc xyz}
} {
db eval {INSERT INTO t1 VALUES(:str)}
}
execsql {
SELECT count(*) FROM t1;
}
} {12}
# Test that both case sensitive and insensitive version of LIKE work.
#
do_test like-1.1 {
execsql {
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
}
} {ABC abc}
do_test like-1.2 {
execsql {
SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
}
} {abc}
do_test like-1.3 {
execsql {
SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
}
} {ABC abc}
do_test like-1.4 {
execsql {
SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
}
} {ABC abc}
do_test like-1.5 {
execsql {
PRAGMA case_sensitive_like=on;
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
}
} {abc}
do_test like-1.6 {
execsql {
SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
}
} {abc}
do_test like-1.7 {
execsql {
SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
}
} {ABC}
do_test like-1.8 {
execsql {
SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
}
} {}
do_test like-1.9 {
execsql {
PRAGMA case_sensitive_like=off;
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
}
} {ABC abc}
# Tests of the REGEXP operator
#
do_test like-2.1 {
proc test_regexp {a b} {
return [regexp $a $b]
}
db function regexp test_regexp
execsql {
SELECT x FROM t1 WHERE x REGEXP 'abc' ORDER BY 1;
}
} {{ABC abc xyz} abc abcd}
do_test like-2.2 {
execsql {
SELECT x FROM t1 WHERE x REGEXP '^abc' ORDER BY 1;
}
} {abc abcd}
# Tests of the MATCH operator
#
do_test like-2.3 {
proc test_match {a b} {
return [string match $a $b]
}
db function match test_match
execsql {
SELECT x FROM t1 WHERE x MATCH '*abc*' ORDER BY 1;
}
} {{ABC abc xyz} abc abcd}
do_test like-2.4 {
execsql {
SELECT x FROM t1 WHERE x MATCH 'abc*' ORDER BY 1;
}
} {abc abcd}
# For the remaining tests, we need to have the like optimizations
# enabled.
#
ifcapable !like_opt {
finish_test
return
}
# This procedure executes the SQL. Then it appends to the result the
# "sort" or "nosort" keyword (as in the cksort procedure above) then
# it appends the ::sqlite_query_plan variable.
#
proc queryplan {sql} {
set ::sqlite_sort_count 0
set data [execsql $sql]
if {$::sqlite_sort_count} {set x sort} {set x nosort}
lappend data $x
return [concat $data $::sqlite_query_plan]
}
# Perform tests on the like optimization.
#
# With no index on t1.x and with case sensitivity turned off, no optimization
# is performed.
#
do_test like-3.1 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
}
} {ABC {ABC abc xyz} abc abcd sort t1 {}}
do_test like-3.2 {
set sqlite_like_count
} {12}
# With an index on t1.x and case sensitivity on, optimize completely.
#
do_test like-3.3 {
set sqlite_like_count 0
execsql {
PRAGMA case_sensitive_like=on;
CREATE INDEX i1 ON t1(x);
}
queryplan {
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
}
} {abc abcd nosort {} i1}
do_test like-3.4 {
set sqlite_like_count
} 0
# Partial optimization when the pattern does not end in '%'
#
do_test like-3.5 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE 'a_c' ORDER BY 1;
}
} {abc nosort {} i1}
do_test like-3.6 {
set sqlite_like_count
} 6
do_test like-3.7 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE 'ab%d' ORDER BY 1;
}
} {abcd abd nosort {} i1}
do_test like-3.8 {
set sqlite_like_count
} 4
do_test like-3.9 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE 'a_c%' ORDER BY 1;
}
} {abc abcd nosort {} i1}
do_test like-3.10 {
set sqlite_like_count
} 6
# No optimization when the pattern begins with a wildcard.
# Note that the index is still used but only for sorting.
#
do_test like-3.11 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE '%bcd' ORDER BY 1;
}
} {abcd bcd nosort {} i1}
do_test like-3.12 {
set sqlite_like_count
} 12
# No optimization for case insensitive LIKE
#
do_test like-3.13 {
set sqlite_like_count 0
queryplan {
PRAGMA case_sensitive_like=off;
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
}
} {ABC {ABC abc xyz} abc abcd nosort {} i1}
do_test like-3.14 {
set sqlite_like_count
} 12
# No optimization without an index.
#
do_test like-3.15 {
set sqlite_like_count 0
queryplan {
PRAGMA case_sensitive_like=on;
DROP INDEX i1;
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
}
} {abc abcd sort t1 {}}
do_test like-3.16 {
set sqlite_like_count
} 12
# No GLOB optimization without an index.
#
do_test like-3.17 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
}
} {abc abcd sort t1 {}}
do_test like-3.18 {
set sqlite_like_count
} 12
# GLOB is optimized regardless of the case_sensitive_like setting.
#
do_test like-3.19 {
set sqlite_like_count 0
queryplan {
CREATE INDEX i1 ON t1(x);
SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
}
} {abc abcd nosort {} i1}
do_test like-3.20 {
set sqlite_like_count
} 0
do_test like-3.21 {
set sqlite_like_count 0
queryplan {
PRAGMA case_sensitive_like=on;
SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
}
} {abc abcd nosort {} i1}
do_test like-3.22 {
set sqlite_like_count
} 0
do_test like-3.23 {
set sqlite_like_count 0
queryplan {
PRAGMA case_sensitive_like=off;
SELECT x FROM t1 WHERE x GLOB 'a[bc]d' ORDER BY 1;
}
} {abd acd nosort {} i1}
do_test like-3.24 {
set sqlite_like_count
} 6
# No optimization if the LHS of the LIKE is not a column name or
# if the RHS is not a string.
#
do_test like-4.1 {
execsql {PRAGMA case_sensitive_like=on}
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1
}
} {abc abcd nosort {} i1}
do_test like-4.2 {
set sqlite_like_count
} 0
do_test like-4.3 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE +x LIKE 'abc%' ORDER BY 1
}
} {abc abcd nosort {} i1}
do_test like-4.4 {
set sqlite_like_count
} 12
do_test like-4.5 {
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE ('ab' || 'c%') ORDER BY 1
}
} {abc abcd nosort {} i1}
do_test like-4.6 {
set sqlite_like_count
} 12
# Collating sequences on the index disable the LIKE optimization.
# Or if the NOCASE collating sequence is used, the LIKE optimization
# is enabled when case_sensitive_like is OFF.
#
do_test like-5.1 {
execsql {PRAGMA case_sensitive_like=off}
set sqlite_like_count 0
queryplan {
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1
}
} {ABC {ABC abc xyz} abc abcd nosort {} i1}
do_test like-5.2 {
set sqlite_like_count
} 12
do_test like-5.3 {
execsql {
CREATE TABLE t2(x COLLATE NOCASE);
INSERT INTO t2 SELECT * FROM t1;
CREATE INDEX i2 ON t2(x COLLATE NOCASE);
}
set sqlite_like_count 0
queryplan {
SELECT x FROM t2 WHERE x LIKE 'abc%' ORDER BY 1
}
} {abc ABC {ABC abc xyz} abcd nosort {} i2}
do_test like-5.4 {
set sqlite_like_count
} 0
do_test like-5.5 {
execsql {
PRAGMA case_sensitive_like=on;
}
set sqlite_like_count 0
queryplan {
SELECT x FROM t2 WHERE x LIKE 'abc%' ORDER BY 1
}
} {abc abcd nosort {} i2}
do_test like-5.6 {
set sqlite_like_count
} 12
do_test like-5.7 {
execsql {
PRAGMA case_sensitive_like=off;
}
set sqlite_like_count 0
queryplan {
SELECT x FROM t2 WHERE x GLOB 'abc*' ORDER BY 1
}
} {abc abcd nosort {} i2}
do_test like-5.8 {
set sqlite_like_count
} 12
finish_test
+448
View File
@@ -0,0 +1,448 @@
# 2001 November 6
#
# 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 regression tests for SQLite library. The
# focus of this file is testing the LIMIT ... OFFSET ... clause
# of SELECT statements.
#
# $Id: limit.test,v 1.30 2006/06/20 11:01:09 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Build some test data
#
execsql {
CREATE TABLE t1(x int, y int);
BEGIN;
}
for {set i 1} {$i<=32} {incr i} {
for {set j 0} {pow(2,$j)<$i} {incr j} {}
execsql "INSERT INTO t1 VALUES([expr {32-$i}],[expr {10-$j}])"
}
execsql {
COMMIT;
}
do_test limit-1.0 {
execsql {SELECT count(*) FROM t1}
} {32}
do_test limit-1.1 {
execsql {SELECT count(*) FROM t1 LIMIT 5}
} {32}
do_test limit-1.2.1 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 5}
} {0 1 2 3 4}
do_test limit-1.2.2 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 5 OFFSET 2}
} {2 3 4 5 6}
do_test limit-1.2.3 {
execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT 5 OFFSET -2}
} {0 1 2 3 4}
do_test limit-1.2.4 {
execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT 2, -5}
} {2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31}
do_test limit-1.2.5 {
execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT -2, 5}
} {0 1 2 3 4}
do_test limit-1.2.6 {
execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT -2, -5}
} {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31}
do_test limit-1.2.7 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 2, 5}
} {2 3 4 5 6}
do_test limit-1.3 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 5 OFFSET 5}
} {5 6 7 8 9}
do_test limit-1.4.1 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 50 OFFSET 30}
} {30 31}
do_test limit-1.4.2 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 30, 50}
} {30 31}
do_test limit-1.5 {
execsql {SELECT x FROM t1 ORDER BY x LIMIT 50 OFFSET 50}
} {}
do_test limit-1.6 {
execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5}
} {0 5 0 5 0 5 1 5 0 5 2 5 0 5 3 5 0 5 4 5}
do_test limit-1.7 {
execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5 OFFSET 32}
} {1 5 0 5 1 5 1 5 1 5 2 5 1 5 3 5 1 5 4 5}
ifcapable {view && subquery} {
do_test limit-2.1 {
execsql {
CREATE VIEW v1 AS SELECT * FROM t1 LIMIT 2;
SELECT count(*) FROM (SELECT * FROM v1);
}
} 2
} ;# ifcapable view
do_test limit-2.2 {
execsql {
CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 2;
SELECT count(*) FROM t2;
}
} 2
ifcapable subquery {
do_test limit-2.3 {
execsql {
SELECT count(*) FROM t1 WHERE rowid IN (SELECT rowid FROM t1 LIMIT 2);
}
} 2
}
ifcapable subquery {
do_test limit-3.1 {
execsql {
SELECT z FROM (SELECT y*10+x AS z FROM t1 ORDER BY x LIMIT 10)
ORDER BY z LIMIT 5;
}
} {50 51 52 53 54}
}
do_test limit-4.1 {
ifcapable subquery {
execsql {
BEGIN;
CREATE TABLE t3(x);
INSERT INTO t3 SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3;
END;
SELECT count(*) FROM t3;
}
} else {
execsql {
BEGIN;
CREATE TABLE t3(x);
INSERT INTO t3 SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1;
}
for {set i 0} {$i<10} {incr i} {
set max_x_t3 [execsql {SELECT max(x) FROM t3}]
execsql "INSERT INTO t3 SELECT x+$max_x_t3 FROM t3;"
}
execsql {
END;
SELECT count(*) FROM t3;
}
}
} {10240}
do_test limit-4.2 {
execsql {
SELECT x FROM t3 LIMIT 2 OFFSET 10000
}
} {10001 10002}
do_test limit-4.3 {
execsql {
CREATE TABLE t4 AS SELECT x,
'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x ||
'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x ||
'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x ||
'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x ||
'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x AS y
FROM t3 LIMIT 1000;
SELECT x FROM t4 ORDER BY y DESC LIMIT 1 OFFSET 999;
}
} {1000}
do_test limit-5.1 {
execsql {
CREATE TABLE t5(x,y);
INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x BETWEEN 10 AND 15
ORDER BY x LIMIT 2;
SELECT * FROM t5 ORDER BY x;
}
} {5 15 6 16}
do_test limit-5.2 {
execsql {
DELETE FROM t5;
INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x BETWEEN 10 AND 15
ORDER BY x DESC LIMIT 2;
SELECT * FROM t5 ORDER BY x;
}
} {9 19 10 20}
do_test limit-5.3 {
execsql {
DELETE FROM t5;
INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x ORDER BY x DESC LIMIT 31;
SELECT * FROM t5 ORDER BY x LIMIT 2;
}
} {-4 6 -3 7}
do_test limit-5.4 {
execsql {
SELECT * FROM t5 ORDER BY x DESC, y DESC LIMIT 2;
}
} {21 41 21 39}
do_test limit-5.5 {
execsql {
DELETE FROM t5;
INSERT INTO t5 SELECT a.x*100+b.x, a.y*100+b.y FROM t1 AS a, t1 AS b
ORDER BY 1, 2 LIMIT 1000;
SELECT count(*), sum(x), sum(y), min(x), max(x), min(y), max(y) FROM t5;
}
} {1000 1528204 593161 0 3107 505 1005}
# There is some contraversy about whether LIMIT 0 should be the same as
# no limit at all or if LIMIT 0 should result in zero output rows.
#
do_test limit-6.1 {
execsql {
BEGIN;
CREATE TABLE t6(a);
INSERT INTO t6 VALUES(1);
INSERT INTO t6 VALUES(2);
INSERT INTO t6 SELECT a+2 FROM t6;
COMMIT;
SELECT * FROM t6;
}
} {1 2 3 4}
do_test limit-6.2 {
execsql {
SELECT * FROM t6 LIMIT -1 OFFSET -1;
}
} {1 2 3 4}
do_test limit-6.3 {
execsql {
SELECT * FROM t6 LIMIT 2 OFFSET -123;
}
} {1 2}
do_test limit-6.4 {
execsql {
SELECT * FROM t6 LIMIT -432 OFFSET 2;
}
} {3 4}
do_test limit-6.5 {
execsql {
SELECT * FROM t6 LIMIT -1
}
} {1 2 3 4}
do_test limit-6.6 {
execsql {
SELECT * FROM t6 LIMIT -1 OFFSET 1
}
} {2 3 4}
do_test limit-6.7 {
execsql {
SELECT * FROM t6 LIMIT 0
}
} {}
do_test limit-6.8 {
execsql {
SELECT * FROM t6 LIMIT 0 OFFSET 1
}
} {}
# Make sure LIMIT works well with compound SELECT statements.
# Ticket #393
#
ifcapable compound {
do_test limit-7.1.1 {
catchsql {
SELECT x FROM t2 LIMIT 5 UNION ALL SELECT a FROM t6;
}
} {1 {LIMIT clause should come after UNION ALL not before}}
do_test limit-7.1.2 {
catchsql {
SELECT x FROM t2 LIMIT 5 UNION SELECT a FROM t6;
}
} {1 {LIMIT clause should come after UNION not before}}
do_test limit-7.1.3 {
catchsql {
SELECT x FROM t2 LIMIT 5 EXCEPT SELECT a FROM t6 LIMIT 3;
}
} {1 {LIMIT clause should come after EXCEPT not before}}
do_test limit-7.1.4 {
catchsql {
SELECT x FROM t2 LIMIT 0,5 INTERSECT SELECT a FROM t6;
}
} {1 {LIMIT clause should come after INTERSECT not before}}
do_test limit-7.2 {
execsql {
SELECT x FROM t2 UNION ALL SELECT a FROM t6 LIMIT 5;
}
} {31 30 1 2 3}
do_test limit-7.3 {
execsql {
SELECT x FROM t2 UNION ALL SELECT a FROM t6 LIMIT 3 OFFSET 1;
}
} {30 1 2}
do_test limit-7.4 {
execsql {
SELECT x FROM t2 UNION ALL SELECT a FROM t6 ORDER BY 1 LIMIT 3 OFFSET 1;
}
} {2 3 4}
do_test limit-7.5 {
execsql {
SELECT x FROM t2 UNION SELECT x+2 FROM t2 LIMIT 2 OFFSET 1;
}
} {31 32}
do_test limit-7.6 {
execsql {
SELECT x FROM t2 UNION SELECT x+2 FROM t2 ORDER BY 1 DESC LIMIT 2 OFFSET 1;
}
} {32 31}
do_test limit-7.7 {
execsql {
SELECT a+9 FROM t6 EXCEPT SELECT y FROM t2 LIMIT 2;
}
} {11 12}
do_test limit-7.8 {
execsql {
SELECT a+9 FROM t6 EXCEPT SELECT y FROM t2 ORDER BY 1 DESC LIMIT 2;
}
} {13 12}
do_test limit-7.9 {
execsql {
SELECT a+26 FROM t6 INTERSECT SELECT x FROM t2 LIMIT 1;
}
} {30}
do_test limit-7.10 {
execsql {
SELECT a+27 FROM t6 INTERSECT SELECT x FROM t2 LIMIT 1;
}
} {30}
do_test limit-7.11 {
execsql {
SELECT a+27 FROM t6 INTERSECT SELECT x FROM t2 LIMIT 1 OFFSET 1;
}
} {31}
do_test limit-7.12 {
execsql {
SELECT a+27 FROM t6 INTERSECT SELECT x FROM t2
ORDER BY 1 DESC LIMIT 1 OFFSET 1;
}
} {30}
} ;# ifcapable compound
# Tests for limit in conjunction with distinct. The distinct should
# occur before both the limit and the offset. Ticket #749.
#
do_test limit-8.1 {
execsql {
SELECT DISTINCT cast(round(x/100) as integer) FROM t3 LIMIT 5;
}
} {0 1 2 3 4}
do_test limit-8.2 {
execsql {
SELECT DISTINCT cast(round(x/100) as integer) FROM t3 LIMIT 5 OFFSET 5;
}
} {5 6 7 8 9}
do_test limit-8.3 {
execsql {
SELECT DISTINCT cast(round(x/100) as integer) FROM t3 LIMIT 5 OFFSET 25;
}
} {25 26 27 28 29}
# Make sure limits on multiple subqueries work correctly.
# Ticket #1035
#
ifcapable subquery {
do_test limit-9.1 {
execsql {
SELECT * FROM (SELECT * FROM t6 LIMIT 3);
}
} {1 2 3}
}
do_test limit-9.2.1 {
execsql {
CREATE TABLE t7 AS SELECT * FROM t6;
}
} {}
ifcapable subquery {
do_test limit-9.2.2 {
execsql {
SELECT * FROM (SELECT * FROM t7 LIMIT 3);
}
} {1 2 3}
}
ifcapable compound {
ifcapable subquery {
do_test limit-9.3 {
execsql {
SELECT * FROM (SELECT * FROM t6 LIMIT 3)
UNION
SELECT * FROM (SELECT * FROM t7 LIMIT 3)
ORDER BY 1
}
} {1 2 3}
do_test limit-9.4 {
execsql {
SELECT * FROM (SELECT * FROM t6 LIMIT 3)
UNION
SELECT * FROM (SELECT * FROM t7 LIMIT 3)
ORDER BY 1
LIMIT 2
}
} {1 2}
}
do_test limit-9.5 {
catchsql {
SELECT * FROM t6 LIMIT 3
UNION
SELECT * FROM t7 LIMIT 3
}
} {1 {LIMIT clause should come after UNION not before}}
}
# Test LIMIT and OFFSET using SQL variables.
do_test limit-10.1 {
set limit 10
db eval {
SELECT x FROM t1 LIMIT :limit;
}
} {31 30 29 28 27 26 25 24 23 22}
do_test limit-10.2 {
set limit 5
set offset 5
db eval {
SELECT x FROM t1 LIMIT :limit OFFSET :offset;
}
} {26 25 24 23 22}
do_test limit-10.3 {
set limit -1
db eval {
SELECT x FROM t1 WHERE x<10 LIMIT :limit;
}
} {9 8 7 6 5 4 3 2 1 0}
do_test limit-10.4 {
set limit 1.5
set rc [catch {
db eval {
SELECT x FROM t1 WHERE x<10 LIMIT :limit;
} } msg]
list $rc $msg
} {1 {datatype mismatch}}
do_test limit-10.5 {
set limit "hello world"
set rc [catch {
db eval {
SELECT x FROM t1 WHERE x<10 LIMIT :limit;
} } msg]
list $rc $msg
} {1 {datatype mismatch}}
ifcapable subquery {
do_test limit-11.1 {
db eval {
SELECT x FROM (SELECT x FROM t1 ORDER BY x LIMIT 0) ORDER BY x
}
} {}
} ;# ifcapable subquery
finish_test
+192
View File
@@ -0,0 +1,192 @@
# 2006 July 14
#
# 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 regression tests for SQLite library. The
# focus of this script is extension loading.
#
# $Id: loadext.test,v 1.8 2006/08/23 20:07:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# The name of the test extension varies by operating system.
#
if {$::tcl_platform(platform) eq "windows"} {
set testextension ./testloadext.dll
} else {
set testextension ./libtestloadext.so
}
# Make sure the test extension actually exists. If it does not
# exist, try to create it. If unable to create it, then skip this
# test file.
#
if {![file exists $testextension]} {
set srcdir [file dir $testdir]/src
set testextsrc $srcdir/test_loadext.c
if {[catch {
exec gcc -Wall -I$srcdir -I. -g -shared $testextsrc -o $testextension
} msg]} {
puts "Skipping loadext tests: Test extension not built..."
puts $msg
finish_test
return
}
}
# Test that loading the extension produces the expected results - adding
# the half() function to the specified database handle.
#
do_test loadext-1.1 {
catchsql {
SELECT half(1.0);
}
} {1 {no such function: half}}
do_test loadext-1.2 {
db enable_load_extension 1
sqlite3_load_extension db $testextension testloadext_init
catchsql {
SELECT half(1.0);
}
} {0 0.5}
# Test that a second database connection (db2) can load the extension also.
#
do_test loadext-1.3 {
sqlite3 db2 test.db
sqlite3_enable_load_extension db2 1
catchsql {
SELECT half(1.0);
} db2
} {1 {no such function: half}}
do_test loadext-1.4 {
sqlite3_load_extension db2 $testextension testloadext_init
catchsql {
SELECT half(1.0);
} db2
} {0 0.5}
# Close the first database connection. Then check that the second database
# can still use the half() function without a problem.
#
do_test loadext-1.5 {
db close
catchsql {
SELECT half(1.0);
} db2
} {0 0.5}
db2 close
sqlite3 db test.db
sqlite3_enable_load_extension db 1
# Try to load an extension for which the file does not exist.
#
do_test loadext-2.1 {
set rc [catch {
sqlite3_load_extension db "${testextension}xx"
} msg]
list $rc $msg
} [list 1 [subst -nocommands \
{unable to open shared library [${testextension}xx]}
]]
# Try to load an extension for which the file is not a shared object
#
do_test loadext-2.2 {
set fd [open "${testextension}xx" w]
puts $fd blah
close $fd
set rc [catch {
sqlite3_load_extension db "${testextension}xx"
} msg]
list $rc $msg
} [list 1 [subst -nocommands \
{unable to open shared library [${testextension}xx]}
]]
# Try to load an extension for which the file is present but the
# entry point is not.
#
do_test loadext-2.3 {
set rc [catch {
sqlite3_load_extension db $testextension icecream
} msg]
list $rc $msg
} [list 1 [subst -nocommands \
{no entry point [icecream] in shared library [$testextension]}
]]
# Try to load an extension for which the entry point fails (returns non-zero)
#
do_test loadext-2.4 {
set rc [catch {
sqlite3_load_extension db $testextension testbrokenext_init
} msg]
list $rc $msg
} {1 {error during initialization: broken!}}
############################################################################
# Tests for the load_extension() SQL function
#
db close
sqlite3 db test.db
sqlite3_enable_load_extension db 1
do_test loadext-3.1 {
catchsql {
SELECT half(5);
}
} {1 {no such function: half}}
do_test loadext-3.2 {
catchsql {
SELECT load_extension($::testextension)
}
} [list 1 "no entry point \[sqlite3_extension_init\]\
in shared library \[$testextension\]"]
do_test loadext-3.3 {
catchsql {
SELECT load_extension($::testextension,'testloadext_init')
}
} {0 {{}}}
do_test loadext-3.4 {
catchsql {
SELECT half(5);
}
} {0 2.5}
# Ticket #1863
# Make sure the extension loading mechanism will not work unless it
# is explicitly enabled.
#
db close
sqlite3 db test.db
do_test loadext-4.1 {
catchsql {
SELECT load_extension($::testextension,'testloadext_init')
}
} {1 {not authorized}}
do_test loadext-4.2 {
sqlite3_enable_load_extension db 1
catchsql {
SELECT load_extension($::testextension,'testloadext_init')
}
} {0 {{}}}
do_test loadext-4.3 {
sqlite3_enable_load_extension db 0
catchsql {
SELECT load_extension($::testextension,'testloadext_init')
}
} {1 {not authorized}}
finish_test
+139
View File
@@ -0,0 +1,139 @@
# 2006 August 23
#
# 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 regression tests for SQLite library. The
# focus of this script is automatic extension loading and the
# sqlite3_auto_extension() API.
#
# $Id: loadext2.test,v 1.1 2006/08/23 20:07:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only run these tests if the approriate APIs are defined
# in the system under test.
#
if {[info command sqlite3_auto_extension_sqr]==""} {
finish_test
return
}
# None of the extension are loaded by default.
#
do_test loadext2-1.1 {
catchsql {
SELECT sqr(2)
}
} {1 {no such function: sqr}}
do_test loadext2-1.2 {
catchsql {
SELECT cube(2)
}
} {1 {no such function: cube}}
# Register auto-loaders. Still functions do not exist.
#
do_test loadext2-1.3 {
sqlite3_auto_extension_sqr
sqlite3_auto_extension_cube
catchsql {
SELECT sqr(2)
}
} {1 {no such function: sqr}}
do_test loadext2-1.4 {
catchsql {
SELECT cube(2)
}
} {1 {no such function: cube}}
# Functions do exist in a new database connection
#
do_test loadext2-1.5 {
sqlite3 db test.db
catchsql {
SELECT sqr(2)
}
} {0 4.0}
do_test loadext2-1.6 {
catchsql {
SELECT cube(2)
}
} {0 8.0}
# Reset extension auto loading. Existing extensions still exist.
#
do_test loadext2-1.7 {
sqlite3_reset_auto_extension
catchsql {
SELECT sqr(2)
}
} {0 4.0}
do_test loadext2-1.8 {
catchsql {
SELECT cube(2)
}
} {0 8.0}
# Register only the sqr() function.
#
do_test loadext2-1.9 {
sqlite3_auto_extension_sqr
sqlite3 db test.db
catchsql {
SELECT sqr(2)
}
} {0 4.0}
do_test loadext2-1.10 {
catchsql {
SELECT cube(2)
}
} {1 {no such function: cube}}
# Register only the cube() function.
#
do_test loadext2-1.11 {
sqlite3_reset_auto_extension
sqlite3_auto_extension_cube
sqlite3 db test.db
catchsql {
SELECT sqr(2)
}
} {1 {no such function: sqr}}
do_test loadext2-1.12 {
catchsql {
SELECT cube(2)
}
} {0 8.0}
# Register a broken entry point.
#
do_test loadext2-1.13 {
sqlite3_auto_extension_broken
set rc [catch {sqlite3 db test.db} errmsg]
lappend rc $errmsg
} {1 {automatic extension loading failed: broken autoext!}}
do_test loadext2-1.14 {
catchsql {
SELECT sqr(2)
}
} {1 {no such function: sqr}}
do_test loadext2-1.15 {
catchsql {
SELECT cube(2)
}
} {0 8.0}
sqlite3_reset_auto_extension
finish_test
+354
View File
@@ -0,0 +1,354 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.33 2006/08/16 16:42:48 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create an alternative connection to the database
#
do_test lock-1.0 {
sqlite3 db2 ./test.db
set dummy {}
} {}
do_test lock-1.1 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {}
do_test lock-1.2 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
} {}
do_test lock-1.3 {
execsql {CREATE TABLE t1(a int, b int)}
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
} {t1}
do_test lock-1.5 {
catchsql {
SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
} db2
} {0 t1}
do_test lock-1.6 {
execsql {INSERT INTO t1 VALUES(1,2)}
execsql {SELECT * FROM t1}
} {1 2}
# Update: The schema is now brought up to date by test lock-1.5.
# do_test lock-1.7.1 {
# catchsql {SELECT * FROM t1} db2
# } {1 {no such table: t1}}
do_test lock-1.7.2 {
catchsql {SELECT * FROM t1} db2
} {0 {1 2}}
do_test lock-1.8 {
execsql {UPDATE t1 SET a=b, b=a} db2
execsql {SELECT * FROM t1} db2
} {2 1}
do_test lock-1.9 {
execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.10 {
execsql {BEGIN TRANSACTION}
execsql {UPDATE t1 SET a = 0 WHERE 0}
execsql {SELECT * FROM t1}
} {2 1}
do_test lock-1.11 {
catchsql {SELECT * FROM t1} db2
} {0 {2 1}}
do_test lock-1.12 {
execsql {ROLLBACK}
catchsql {SELECT * FROM t1}
} {0 {2 1}}
do_test lock-1.13 {
execsql {CREATE TABLE t2(x int, y int)}
execsql {INSERT INTO t2 VALUES(8,9)}
execsql {SELECT * FROM t2}
} {8 9}
do_test lock-1.14.1 {
catchsql {SELECT * FROM t2} db2
} {1 {no such table: t2}}
do_test lock-1.14.2 {
catchsql {SELECT * FROM t1} db2
} {0 {2 1}}
do_test lock-1.15 {
catchsql {SELECT * FROM t2} db2
} {0 {8 9}}
do_test lock-1.16 {
db eval {SELECT * FROM t1} qv {
set x [db eval {SELECT * FROM t1}]
}
set x
} {2 1}
do_test lock-1.17 {
db eval {SELECT * FROM t1} qv {
set x [db eval {SELECT * FROM t2}]
}
set x
} {8 9}
# You cannot UPDATE a table from within the callback of a SELECT
# on that same table because the SELECT has the table locked.
#
# 2006-08-16: Reads no longer block writes within the same
# database connection.
#
#do_test lock-1.18 {
# db eval {SELECT * FROM t1} qv {
# set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
# lappend r $msg
# }
# set r
#} {1 {database table is locked}}
# But you can UPDATE a different table from the one that is used in
# the SELECT.
#
do_test lock-1.19 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
lappend r $msg
}
set r
} {0 {}}
do_test lock-1.20 {
execsql {SELECT * FROM t2}
} {9 8}
# It is possible to do a SELECT of the same table within the
# callback of another SELECT on that same table because two
# or more read-only cursors can be open at once.
#
do_test lock-1.21 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {SELECT a FROM t1}} msg]
lappend r $msg
}
set r
} {0 2}
# Under UNIX you can do two SELECTs at once with different database
# connections, because UNIX supports reader/writer locks. Under windows,
# this is not possible.
#
if {$::tcl_platform(platform)=="unix"} {
do_test lock-1.22 {
db eval {SELECT * FROM t1} qv {
set r [catch {db2 eval {SELECT a FROM t1}} msg]
lappend r $msg
}
set r
} {0 2}
}
integrity_check lock-1.23
# If one thread has a transaction another thread cannot start
# a transaction. -> Not true in version 3.0. But if one thread
# as a RESERVED lock another thread cannot acquire one.
#
do_test lock-2.1 {
execsql {BEGIN TRANSACTION}
execsql {UPDATE t1 SET a = 0 WHERE 0}
execsql {BEGIN TRANSACTION} db2
set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
execsql {ROLLBACK} db2
lappend r $msg
} {1 {database is locked}}
# A thread can read when another has a RESERVED lock.
#
do_test lock-2.2 {
catchsql {SELECT * FROM t2} db2
} {0 {9 8}}
# If the other thread (the one that does not hold the transaction with
# a RESERVED lock) tries to get a RESERVED lock, we do get a busy callback
# as long as we were not orginally holding a READ lock.
#
do_test lock-2.3.1 {
proc callback {count} {
set ::callback_value $count
break
}
set ::callback_value {}
db2 busy callback
# db2 does not hold a lock so we should get a busy callback here
set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} 0}
do_test lock-2.3.2 {
set ::callback_value {}
execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2
# This time db2 does hold a read lock. No busy callback this time.
set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} {}}
catch {execsql {ROLLBACK} db2}
do_test lock-2.4.1 {
proc callback {count} {
lappend ::callback_value $count
if {$count>4} break
}
set ::callback_value {}
db2 busy callback
# We get a busy callback because db2 is not holding a lock
set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} {0 1 2 3 4 5}}
do_test lock-2.4.2 {
proc callback {count} {
lappend ::callback_value $count
if {$count>4} break
}
set ::callback_value {}
db2 busy callback
execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2
# No busy callback this time because we are holding a lock
set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
lappend r $msg
lappend r $::callback_value
} {1 {database is locked} {}}
catch {execsql {ROLLBACK} db2}
do_test lock-2.5 {
proc callback {count} {
lappend ::callback_value $count
if {$count>4} break
}
set ::callback_value {}
db2 busy callback
set r [catch {execsql {SELECT * FROM t1} db2} msg]
lappend r $msg
lappend r $::callback_value
} {0 {2 1} {}}
execsql {ROLLBACK}
# Test the built-in busy timeout handler
#
do_test lock-2.8 {
db2 timeout 400
execsql BEGIN
execsql {UPDATE t1 SET a = 0 WHERE 0}
catchsql {BEGIN EXCLUSIVE;} db2
} {1 {database is locked}}
do_test lock-2.9 {
db2 timeout 0
execsql COMMIT
} {}
integrity_check lock-2.10
# Try to start two transactions in a row
#
do_test lock-3.1 {
execsql {BEGIN TRANSACTION}
set r [catch {execsql {BEGIN TRANSACTION}} msg]
execsql {ROLLBACK}
lappend r $msg
} {1 {cannot start a transaction within a transaction}}
integrity_check lock-3.2
# Make sure the busy handler and error messages work when
# opening a new pointer to the database while another pointer
# has the database locked.
#
do_test lock-4.1 {
db2 close
catch {db eval ROLLBACK}
db eval BEGIN
db eval {UPDATE t1 SET a=0 WHERE 0}
sqlite3 db2 ./test.db
catchsql {UPDATE t1 SET a=0} db2
} {1 {database is locked}}
do_test lock-4.2 {
set ::callback_value {}
set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
lappend rc $msg $::callback_value
} {1 {database is locked} {}}
do_test lock-4.3 {
proc callback {count} {
lappend ::callback_value $count
if {$count>4} break
}
db2 busy callback
set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
lappend rc $msg $::callback_value
} {1 {database is locked} {0 1 2 3 4 5}}
execsql {ROLLBACK}
# When one thread is writing, other threads cannot read. Except if the
# writing thread is writing to its temporary tables, the other threads
# can still read. -> Not so in 3.0. One thread can read while another
# holds a RESERVED lock.
#
proc tx_exec {sql} {
db2 eval $sql
}
do_test lock-5.1 {
execsql {
SELECT * FROM t1
}
} {2 1}
do_test lock-5.2 {
db function tx_exec tx_exec
catchsql {
INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1');
}
} {0 {}}
ifcapable tempdb {
do_test lock-5.3 {
execsql {
CREATE TEMP TABLE t3(x);
SELECT * FROM t3;
}
} {}
do_test lock-5.4 {
catchsql {
INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1');
}
} {0 {}}
do_test lock-5.5 {
execsql {
SELECT * FROM t3;
}
} {8}
do_test lock-5.6 {
catchsql {
UPDATE t1 SET a=tx_exec('SELECT x FROM t2');
}
} {0 {}}
do_test lock-5.7 {
execsql {
SELECT * FROM t1;
}
} {9 1 9 8}
do_test lock-5.8 {
catchsql {
UPDATE t3 SET x=tx_exec('SELECT x FROM t2');
}
} {0 {}}
do_test lock-5.9 {
execsql {
SELECT * FROM t3;
}
} {9}
}
do_test lock-999.1 {
rename db2 {}
} {}
finish_test
+163
View File
@@ -0,0 +1,163 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is database locks between competing processes.
#
# $Id: lock2.test,v 1.6 2005/09/17 16:48:19 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Launch another testfixture process to be controlled by this one. A
# channel name is returned that may be passed as the first argument to proc
# 'testfixture' to execute a command. The child testfixture process is shut
# down by closing the channel.
proc launch_testfixture {} {
set chan [open "|[file join . testfixture] tf_main.tcl" r+]
fconfigure $chan -buffering line
return $chan
}
# Execute a command in a child testfixture process, connected by two-way
# channel $chan. Return the result of the command, or an error message.
proc testfixture {chan cmd} {
puts $chan $cmd
puts $chan OVER
set r ""
while { 1 } {
set line [gets $chan]
if { $line == "OVER" } {
return $r
}
append r $line
}
}
# Write the main loop for the child testfixture processes into file
# tf_main.tcl. The parent (this script) interacts with the child processes
# via a two way pipe. The parent writes a script to the stdin of the child
# process, followed by the word "OVER" on a line of it's own. The child
# process evaluates the script and writes the results to stdout, followed
# by an "OVER" of its own.
set f [open tf_main.tcl w]
puts $f {
set l [open log w]
set script ""
while {![eof stdin]} {
flush stdout
set line [gets stdin]
puts $l "READ $line"
if { $line == "OVER" } {
catch {eval $script} result
puts $result
puts $l "WRITE $result"
puts OVER
puts $l "WRITE OVER"
flush stdout
set script ""
} else {
append script $line
append script " ; "
}
}
close $l
}
close $f
# Simple locking test case:
#
# lock2-1.1: Connect a second process to the database.
# lock2-1.2: Establish a RESERVED lock with this process.
# lock2-1.3: Get a SHARED lock with the second process.
# lock2-1.4: Try for a RESERVED lock with process 2. This fails.
# lock2-1.5: Try to upgrade the first process to EXCLUSIVE, this fails so
# it gets PENDING.
# lock2-1.6: Release the SHARED lock held by the second process.
# lock2-1.7: Attempt to reaquire a SHARED lock with the second process.
# this fails due to the PENDING lock.
# lock2-1.8: Ensure the first process can now upgrade to EXCLUSIVE.
#
do_test lock2-1.1 {
set ::tf1 [launch_testfixture]
testfixture $::tf1 "set sqlite_pending_byte $::sqlite_pending_byte"
testfixture $::tf1 {
sqlite3 db test.db -key xyzzy
db eval {select * from sqlite_master}
}
} {}
do_test lock2-1.1.1 {
execsql {pragma lock_status}
} {main unlocked temp closed}
do_test lock2-1.2 {
execsql {
BEGIN;
CREATE TABLE abc(a, b, c);
}
} {}
do_test lock2-1.3 {
testfixture $::tf1 {
db eval {
BEGIN;
SELECT * FROM sqlite_master;
}
}
} {}
do_test lock2-1.4 {
testfixture $::tf1 {
db eval {
CREATE TABLE def(d, e, f)
}
}
} {database is locked}
do_test lock2-1.5 {
catchsql {
COMMIT;
}
} {1 {database is locked}}
do_test lock2-1.6 {
testfixture $::tf1 {
db eval {
SELECT * FROM sqlite_master;
COMMIT;
}
}
} {}
do_test lock2-1.7 {
testfixture $::tf1 {
db eval {
BEGIN;
SELECT * FROM sqlite_master;
}
}
} {database is locked}
do_test lock2-1.8 {
catchsql {
COMMIT;
}
} {0 {}}
do_test lock2-1.9 {
execsql {
SELECT * FROM sqlite_master;
}
} "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}"
do_test lock2-1.10 {
testfixture $::tf1 {
db eval {
SELECT * FROM sqlite_master;
}
}
} "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}"
catch {testfixture $::tf1 {db close}}
catch {close $::tf1}
finish_test
+78
View File
@@ -0,0 +1,78 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this script is database locks and the operation of the
# DEFERRED, IMMEDIATE, and EXCLUSIVE keywords as modifiers to the
# BEGIN command.
#
# $Id: lock3.test,v 1.1 2004/10/05 02:41:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Establish two connections to the same database. Put some
# sample data into the database.
#
do_test lock3-1.1 {
sqlite3 db2 test.db
execsql {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
}
execsql {
SELECT * FROM t1
} db2
} 1
# Get a deferred lock on the database using one connection. The
# other connection should still be able to write.
#
do_test lock3-2.1 {
execsql {BEGIN DEFERRED TRANSACTION}
execsql {INSERT INTO t1 VALUES(2)} db2
execsql {END TRANSACTION}
execsql {SELECT * FROM t1}
} {1 2}
# Get an immediate lock on the database using one connection. The
# other connection should be able to read the database but not write
# it.
#
do_test lock3-3.1 {
execsql {BEGIN IMMEDIATE TRANSACTION}
catchsql {SELECT * FROM t1} db2
} {0 {1 2}}
do_test lock3-3.2 {
catchsql {INSERT INTO t1 VALUES(3)} db2
} {1 {database is locked}}
do_test lock3-3.3 {
execsql {END TRANSACTION}
} {}
# Get an exclusive lock on the database using one connection. The
# other connection should be unable to read or write the database.
#
do_test lock3-4.1 {
execsql {BEGIN EXCLUSIVE TRANSACTION}
catchsql {SELECT * FROM t1} db2
} {1 {database is locked}}
do_test lock3-4.2 {
catchsql {INSERT INTO t1 VALUES(3)} db2
} {1 {database is locked}}
do_test lock3-4.3 {
execsql {END TRANSACTION}
} {}
catch {db2 close}
finish_test
+319
View File
@@ -0,0 +1,319 @@
# 2001 September 15
#
# 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 regression tests for SQLite library. The
# focus of this file is exercising the code in main.c.
#
# $Id: main.test,v 1.25 2006/02/09 22:24:41 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Only do the next group of tests if the sqlite3_complete API is available
#
ifcapable {complete} {
# Tests of the sqlite_complete() function.
#
do_test main-1.1 {
db complete {This is a test}
} {0}
do_test main-1.2 {
db complete {
}
} {1}
do_test main-1.3 {
db complete {
-- a comment ;
}
} {1}
do_test main-1.4 {
db complete {
-- a comment ;
;
}
} {1}
do_test main-1.5 {
db complete {DROP TABLE 'xyz;}
} {0}
do_test main-1.6 {
db complete {DROP TABLE 'xyz';}
} {1}
do_test main-1.7 {
db complete {DROP TABLE "xyz;}
} {0}
do_test main-1.8 {
db complete {DROP TABLE "xyz';}
} {0}
do_test main-1.9 {
db complete {DROP TABLE "xyz";}
} {1}
do_test main-1.10 {
db complete {DROP TABLE xyz; hi}
} {0}
do_test main-1.11 {
db complete {DROP TABLE xyz; }
} {1}
do_test main-1.12 {
db complete {DROP TABLE xyz; -- hi }
} {1}
do_test main-1.13 {
db complete {DROP TABLE xyz; -- hi
}
} {1}
do_test main-1.14 {
db complete {SELECT a-b FROM t1; }
} {1}
do_test main-1.15 {
db complete {SELECT a/e FROM t1 }
} {0}
do_test main-1.16 {
db complete {
CREATE TABLE abc(x,y);
}
} {1}
ifcapable {trigger} {
do_test main-1.17 {
db complete {
CREATE TRIGGER xyz AFTER DELETE abc BEGIN UPDATE pqr;
}
} {0}
do_test main-1.18 {
db complete {
CREATE TRIGGER xyz AFTER DELETE abc BEGIN UPDATE pqr; END;
}
} {1}
do_test main-1.19 {
db complete {
CREATE TRIGGER xyz AFTER DELETE abc BEGIN
UPDATE pqr;
unknown command;
}
} {0}
do_test main-1.20 {
db complete {
CREATE TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr;
}
} {0}
do_test main-1.21 {
db complete {
CREATE TRIGGER xyz AFTER DELETE end BEGIN
SELECT a, b FROM end;
}
} {0}
do_test main-1.22 {
db complete {
CREATE TRIGGER xyz AFTER DELETE end BEGIN
SELECT a, b FROM end;
END;
}
} {1}
do_test main-1.23 {
db complete {
CREATE TRIGGER xyz AFTER DELETE end BEGIN
SELECT a, b FROM end;
END;
SELECT a, b FROM end;
}
} {1}
do_test main-1.24 {
db complete {
CREATE TRIGGER xyz AFTER DELETE [;end;] BEGIN
UPDATE pqr;
}
} {0}
do_test main-1.25 {
db complete {
CREATE TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=[;end;];;;
}
} {0}
do_test main-1.26 {
db complete {
CREATE -- a comment
TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {0}
do_test main-1.27.1 {
db complete {
CREATE -- a comment
TRIGGERX xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {1}
do_test main-1.27.2 {
db complete {
CREATE/**/TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {0}
ifcapable {explain} {
do_test main-1.27.3 {
db complete {
/* */ EXPLAIN -- A comment
CREATE/**/TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {0}
}
do_test main-1.27.4 {
db complete {
BOGUS token
CREATE TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {1}
ifcapable {explain} {
do_test main-1.27.5 {
db complete {
EXPLAIN
CREATE TEMP TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {0}
}
do_test main-1.28 {
db complete {
CREATE TEMPORARY TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
}
} {0}
do_test main-1.29 {
db complete {
CREATE TRIGGER xyz AFTER DELETE backend BEGIN
UPDATE pqr SET a=5;
EXPLAIN select * from xyz;
}
} {0}
}
do_test main-1.30 {
db complete {
CREATE TABLE /* In comment ; */
}
} {0}
do_test main-1.31 {
db complete {
CREATE TABLE /* In comment ; */ hi;
}
} {1}
do_test main-1.31 {
db complete {
CREATE TABLE /* In comment ; */;
}
} {1}
do_test main-1.32 {
db complete {
stuff;
/*
CREATE TABLE
multiple lines
of text
*/
}
} {1}
do_test main-1.33 {
db complete {
/*
CREATE TABLE
multiple lines
of text;
}
} {0}
do_test main-1.34 {
db complete {
/*
CREATE TABLE
multiple lines "*/
of text;
}
} {1}
do_test main-1.35 {
db complete {hi /**/ there;}
} {1}
do_test main-1.36 {
db complete {hi there/***/;}
} {1}
} ;# end ifcapable {complete}
# Try to open a database with a corrupt database file.
#
do_test main-2.0 {
catch {db close}
file delete -force test.db
set fd [open test.db w]
puts $fd hi!
close $fd
set v [catch {sqlite3 db test.db} msg]
if {$v} {lappend v $msg} {lappend v {}}
} {0 {}}
# Here are some tests for tokenize.c.
#
do_test main-3.1 {
catch {db close}
foreach f [glob -nocomplain testdb/*] {file delete -force $f}
file delete -force testdb
sqlite3 db testdb
set v [catch {execsql {SELECT * from T1 where x!!5}} msg]
lappend v $msg
} {1 {unrecognized token: "!!"}}
do_test main-3.2 {
catch {db close}
foreach f [glob -nocomplain testdb/*] {file delete -force $f}
file delete -force testdb
sqlite3 db testdb
set v [catch {execsql {SELECT * from T1 where ^x}} msg]
lappend v $msg
} {1 {unrecognized token: "^"}}
do_test main-3.2.2 {
catchsql {select 'abc}
} {1 {unrecognized token: "'abc"}}
do_test main-3.2.3 {
catchsql {select "abc}
} {1 {unrecognized token: ""abc"}}
do_test main-3.3 {
catch {db close}
foreach f [glob -nocomplain testdb/*] {file delete -force $f}
file delete -force testdb
sqlite3 db testdb
execsql {
create table T1(X REAL); /* C-style comments allowed */
insert into T1 values(0.5);
insert into T1 values(0.5e2);
insert into T1 values(0.5e-002);
insert into T1 values(5e-002);
insert into T1 values(-5.0e-2);
insert into T1 values(-5.1e-2);
insert into T1 values(0.5e2);
insert into T1 values(0.5E+02);
insert into T1 values(5E+02);
insert into T1 values(5.0E+03);
select x*10 from T1 order by x*5;
}
} {-0.51 -0.5 0.05 0.5 5.0 500.0 500.0 500.0 5000.0 50000.0}
do_test main-3.4 {
set v [catch {execsql {create bogus}} msg]
lappend v $msg
} {1 {near "bogus": syntax error}}
do_test main-3.5 {
set v [catch {execsql {create}} msg]
lappend v $msg
} {1 {near "create": syntax error}}
do_test main-3.6 {
catchsql {SELECT 'abc' + #9}
} {1 {near "#9": syntax error}}
finish_test

Some files were not shown because too many files have changed in this diff Show More