mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-24 13:12:03 +00:00
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:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user