sl@0: # 2004 November 12 sl@0: # sl@0: # The author disclaims copyright to this source code. In place of sl@0: # a legal notice, here is a blessing: sl@0: # sl@0: # May you do good and not evil. sl@0: # May you find forgiveness for yourself and forgive others. sl@0: # May you share freely, never taking more than you give. sl@0: # sl@0: #************************************************************************* sl@0: # This file implements regression tests for SQLite library. The sl@0: # focus of this script is testing the AUTOINCREMENT features. sl@0: # sl@0: # $Id: autoinc.test,v 1.13 2008/08/11 18:44:58 drh Exp $ sl@0: # sl@0: sl@0: set testdir [file dirname $argv0] sl@0: source $testdir/tester.tcl sl@0: sl@0: # If the library is not compiled with autoincrement support then sl@0: # skip all tests in this file. sl@0: # sl@0: ifcapable {!autoinc} { sl@0: finish_test sl@0: return sl@0: } sl@0: sl@0: # The database is initially empty. sl@0: # sl@0: do_test autoinc-1.1 { sl@0: execsql { sl@0: SELECT name FROM sqlite_master WHERE type='table'; sl@0: } sl@0: } {} sl@0: sl@0: # Add a table with the AUTOINCREMENT feature. Verify that the sl@0: # SQLITE_SEQUENCE table gets created. sl@0: # sl@0: do_test autoinc-1.2 { sl@0: execsql { sl@0: CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y); sl@0: SELECT name FROM sqlite_master WHERE type='table'; sl@0: } sl@0: } {t1 sqlite_sequence} sl@0: sl@0: # The SQLITE_SEQUENCE table is initially empty sl@0: # sl@0: do_test autoinc-1.3 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {} sl@0: do_test autoinc-1.3.1 { sl@0: catchsql { sl@0: CREATE INDEX seqidx ON sqlite_sequence(name) sl@0: } sl@0: } {1 {table sqlite_sequence may not be indexed}} sl@0: sl@0: # Close and reopen the database. Verify that everything is still there. sl@0: # sl@0: do_test autoinc-1.4 { sl@0: db close sl@0: sqlite3 db test.db sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {} sl@0: sl@0: # We are not allowed to drop the sqlite_sequence table. sl@0: # sl@0: do_test autoinc-1.5 { sl@0: catchsql {DROP TABLE sqlite_sequence} sl@0: } {1 {table sqlite_sequence may not be dropped}} sl@0: do_test autoinc-1.6 { sl@0: execsql {SELECT name FROM sqlite_master WHERE type='table'} sl@0: } {t1 sqlite_sequence} sl@0: sl@0: # Insert an entries into the t1 table and make sure the largest key sl@0: # is always recorded in the sqlite_sequence table. sl@0: # sl@0: do_test autoinc-2.1 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence sl@0: } sl@0: } {} sl@0: do_test autoinc-2.2 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(12,34); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 12} sl@0: do_test autoinc-2.3 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(1,23); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 12} sl@0: do_test autoinc-2.4 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(123,456); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 123} sl@0: do_test autoinc-2.5 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(NULL,567); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 124} sl@0: do_test autoinc-2.6 { sl@0: execsql { sl@0: DELETE FROM t1 WHERE y=567; sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 124} sl@0: do_test autoinc-2.7 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(NULL,567); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 125} sl@0: do_test autoinc-2.8 { sl@0: execsql { sl@0: DELETE FROM t1; sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 125} sl@0: do_test autoinc-2.9 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(12,34); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 125} sl@0: do_test autoinc-2.10 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(125,456); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 125} sl@0: do_test autoinc-2.11 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(-1234567,-1); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 125} sl@0: do_test autoinc-2.12 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(234,5678); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 234} sl@0: do_test autoinc-2.13 { sl@0: execsql { sl@0: DELETE FROM t1; sl@0: INSERT INTO t1 VALUES(NULL,1); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 235} sl@0: do_test autoinc-2.14 { sl@0: execsql { sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1} sl@0: sl@0: # Manually change the autoincrement values in sqlite_sequence. sl@0: # sl@0: do_test autoinc-2.20 { sl@0: execsql { sl@0: UPDATE sqlite_sequence SET seq=1234 WHERE name='t1'; sl@0: INSERT INTO t1 VALUES(NULL,2); sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2} sl@0: do_test autoinc-2.21 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 1235} sl@0: do_test autoinc-2.22 { sl@0: execsql { sl@0: UPDATE sqlite_sequence SET seq=NULL WHERE name='t1'; sl@0: INSERT INTO t1 VALUES(NULL,3); sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2 1236 3} sl@0: do_test autoinc-2.23 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 1236} sl@0: do_test autoinc-2.24 { sl@0: execsql { sl@0: UPDATE sqlite_sequence SET seq='a-string' WHERE name='t1'; sl@0: INSERT INTO t1 VALUES(NULL,4); sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2 1236 3 1237 4} sl@0: do_test autoinc-2.25 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 1237} sl@0: do_test autoinc-2.26 { sl@0: execsql { sl@0: DELETE FROM sqlite_sequence WHERE name='t1'; sl@0: INSERT INTO t1 VALUES(NULL,5); sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2 1236 3 1237 4 1238 5} sl@0: do_test autoinc-2.27 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 1238} sl@0: do_test autoinc-2.28 { sl@0: execsql { sl@0: UPDATE sqlite_sequence SET seq='12345678901234567890' sl@0: WHERE name='t1'; sl@0: INSERT INTO t1 VALUES(NULL,6); sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2 1236 3 1237 4 1238 5 1239 6} sl@0: do_test autoinc-2.29 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 1239} sl@0: sl@0: # Test multi-row inserts sl@0: # sl@0: do_test autoinc-2.50 { sl@0: execsql { sl@0: DELETE FROM t1 WHERE y>=3; sl@0: INSERT INTO t1 SELECT NULL, y+2 FROM t1; sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2 1240 3 1241 4} sl@0: do_test autoinc-2.51 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence sl@0: } sl@0: } {t1 1241} sl@0: sl@0: ifcapable tempdb { sl@0: do_test autoinc-2.52 { sl@0: execsql { sl@0: CREATE TEMP TABLE t2 AS SELECT y FROM t1; sl@0: } sl@0: execsql { sl@0: INSERT INTO t1 SELECT NULL, y+4 FROM t2; sl@0: SELECT * FROM t1; sl@0: } sl@0: } {235 1 1235 2 1240 3 1241 4 1242 5 1243 6 1244 7 1245 8} sl@0: do_test autoinc-2.53 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence sl@0: } sl@0: } {t1 1245} sl@0: do_test autoinc-2.54 { sl@0: execsql { sl@0: DELETE FROM t1; sl@0: INSERT INTO t1 SELECT NULL, y FROM t2; sl@0: SELECT * FROM t1; sl@0: } sl@0: } {1246 1 1247 2 1248 3 1249 4} sl@0: do_test autoinc-2.55 { sl@0: execsql { sl@0: SELECT * FROM sqlite_sequence sl@0: } sl@0: } {t1 1249} sl@0: } sl@0: sl@0: # Create multiple AUTOINCREMENT tables. Make sure all sequences are sl@0: # tracked separately and do not interfere with one another. sl@0: # sl@0: do_test autoinc-2.70 { sl@0: catchsql { sl@0: DROP TABLE t2; sl@0: } sl@0: execsql { sl@0: CREATE TABLE t2(d, e INTEGER PRIMARY KEY AUTOINCREMENT, f); sl@0: INSERT INTO t2(d) VALUES(1); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } [ifcapable tempdb {list t1 1249 t2 1} else {list t1 1241 t2 1}] sl@0: do_test autoinc-2.71 { sl@0: execsql { sl@0: INSERT INTO t2(d) VALUES(2); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } [ifcapable tempdb {list t1 1249 t2 2} else {list t1 1241 t2 2}] sl@0: do_test autoinc-2.72 { sl@0: execsql { sl@0: INSERT INTO t1(x) VALUES(10000); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 10000 t2 2} sl@0: do_test autoinc-2.73 { sl@0: execsql { sl@0: CREATE TABLE t3(g INTEGER PRIMARY KEY AUTOINCREMENT, h); sl@0: INSERT INTO t3(h) VALUES(1); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 10000 t2 2 t3 1} sl@0: do_test autoinc-2.74 { sl@0: execsql { sl@0: INSERT INTO t2(d,e) VALUES(3,100); sl@0: SELECT * FROM sqlite_sequence; sl@0: } sl@0: } {t1 10000 t2 100 t3 1} sl@0: sl@0: sl@0: # When a table with an AUTOINCREMENT is deleted, the corresponding entry sl@0: # in the SQLITE_SEQUENCE table should also be deleted. But the SQLITE_SEQUENCE sl@0: # table itself should remain behind. sl@0: # sl@0: do_test autoinc-3.1 { sl@0: execsql {SELECT name FROM sqlite_sequence} sl@0: } {t1 t2 t3} sl@0: do_test autoinc-3.2 { sl@0: execsql { sl@0: DROP TABLE t1; sl@0: SELECT name FROM sqlite_sequence; sl@0: } sl@0: } {t2 t3} sl@0: do_test autoinc-3.3 { sl@0: execsql { sl@0: DROP TABLE t3; sl@0: SELECT name FROM sqlite_sequence; sl@0: } sl@0: } {t2} sl@0: do_test autoinc-3.4 { sl@0: execsql { sl@0: DROP TABLE t2; sl@0: SELECT name FROM sqlite_sequence; sl@0: } sl@0: } {} sl@0: sl@0: # AUTOINCREMENT on TEMP tables. sl@0: # sl@0: ifcapable tempdb { sl@0: do_test autoinc-4.1 { sl@0: execsql { sl@0: SELECT 1, name FROM sqlite_master WHERE type='table'; sl@0: SELECT 2, name FROM sqlite_temp_master WHERE type='table'; sl@0: } sl@0: } {1 sqlite_sequence} sl@0: do_test autoinc-4.2 { sl@0: execsql { sl@0: CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y); sl@0: CREATE TEMP TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b); sl@0: SELECT 1, name FROM sqlite_master WHERE type='table'; sl@0: SELECT 2, name FROM sqlite_temp_master WHERE type='table'; sl@0: } sl@0: } {1 sqlite_sequence 1 t1 2 t3 2 sqlite_sequence} sl@0: do_test autoinc-4.3 { sl@0: execsql { sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {} sl@0: do_test autoinc-4.4 { sl@0: execsql { sl@0: INSERT INTO t1 VALUES(10,1); sl@0: INSERT INTO t3 VALUES(20,2); sl@0: INSERT INTO t1 VALUES(NULL,3); sl@0: INSERT INTO t3 VALUES(NULL,4); sl@0: } sl@0: } {} sl@0: sl@0: ifcapable compound { sl@0: do_test autoinc-4.4.1 { sl@0: execsql { sl@0: SELECT * FROM t1 UNION ALL SELECT * FROM t3; sl@0: } sl@0: } {10 1 11 3 20 2 21 4} sl@0: } ;# ifcapable compound sl@0: sl@0: do_test autoinc-4.5 { sl@0: execsql { sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {1 t1 11 2 t3 21} sl@0: do_test autoinc-4.6 { sl@0: execsql { sl@0: INSERT INTO t1 SELECT * FROM t3; sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {1 t1 21 2 t3 21} sl@0: do_test autoinc-4.7 { sl@0: execsql { sl@0: INSERT INTO t3 SELECT x+100, y FROM t1; sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {1 t1 21 2 t3 121} sl@0: do_test autoinc-4.8 { sl@0: execsql { sl@0: DROP TABLE t3; sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {1 t1 21} sl@0: do_test autoinc-4.9 { sl@0: execsql { sl@0: CREATE TEMP TABLE t2(p INTEGER PRIMARY KEY AUTOINCREMENT, q); sl@0: INSERT INTO t2 SELECT * FROM t1; sl@0: DROP TABLE t1; sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {2 t2 21} sl@0: do_test autoinc-4.10 { sl@0: execsql { sl@0: DROP TABLE t2; sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: } sl@0: } {} sl@0: } sl@0: sl@0: # Make sure AUTOINCREMENT works on ATTACH-ed tables. sl@0: # sl@0: ifcapable tempdb&&attach { sl@0: do_test autoinc-5.1 { sl@0: file delete -force test2.db sl@0: file delete -force test2.db-journal sl@0: sqlite3 db2 test2.db sl@0: execsql { sl@0: CREATE TABLE t4(m INTEGER PRIMARY KEY AUTOINCREMENT, n); sl@0: CREATE TABLE t5(o, p INTEGER PRIMARY KEY AUTOINCREMENT); sl@0: } db2; sl@0: execsql { sl@0: ATTACH 'test2.db' as aux; sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: SELECT 3, * FROM aux.sqlite_sequence; sl@0: } sl@0: } {} sl@0: do_test autoinc-5.2 { sl@0: execsql { sl@0: INSERT INTO t4 VALUES(NULL,1); sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: SELECT 3, * FROM aux.sqlite_sequence; sl@0: } sl@0: } {3 t4 1} sl@0: do_test autoinc-5.3 { sl@0: execsql { sl@0: INSERT INTO t5 VALUES(100,200); sl@0: SELECT * FROM sqlite_sequence sl@0: } db2 sl@0: } {t4 1 t5 200} sl@0: do_test autoinc-5.4 { sl@0: execsql { sl@0: SELECT 1, * FROM main.sqlite_sequence; sl@0: SELECT 2, * FROM temp.sqlite_sequence; sl@0: SELECT 3, * FROM aux.sqlite_sequence; sl@0: } sl@0: } {3 t4 1 3 t5 200} sl@0: } sl@0: sl@0: # Requirement REQ00310: Make sure an insert fails if the sequence is sl@0: # already at its maximum value. sl@0: # sl@0: ifcapable {rowid32} { sl@0: do_test autoinc-6.1 { sl@0: execsql { sl@0: CREATE TABLE t6(v INTEGER PRIMARY KEY AUTOINCREMENT, w); sl@0: INSERT INTO t6 VALUES(2147483647,1); sl@0: SELECT seq FROM main.sqlite_sequence WHERE name='t6'; sl@0: } sl@0: } 2147483647 sl@0: } sl@0: ifcapable {!rowid32} { sl@0: do_test autoinc-6.1 { sl@0: execsql { sl@0: CREATE TABLE t6(v INTEGER PRIMARY KEY AUTOINCREMENT, w); sl@0: INSERT INTO t6 VALUES(9223372036854775807,1); sl@0: SELECT seq FROM main.sqlite_sequence WHERE name='t6'; sl@0: } sl@0: } 9223372036854775807 sl@0: } sl@0: do_test autoinc-6.2 { sl@0: catchsql { sl@0: INSERT INTO t6 VALUES(NULL,1); sl@0: } sl@0: } {1 {database or disk is full}} sl@0: sl@0: # Allow the AUTOINCREMENT keyword inside the parentheses sl@0: # on a separate PRIMARY KEY designation. sl@0: # sl@0: do_test autoinc-7.1 { sl@0: execsql { sl@0: CREATE TABLE t7(x INTEGER, y REAL, PRIMARY KEY(x AUTOINCREMENT)); sl@0: INSERT INTO t7(y) VALUES(123); sl@0: INSERT INTO t7(y) VALUES(234); sl@0: DELETE FROM t7; sl@0: INSERT INTO t7(y) VALUES(345); sl@0: SELECT * FROM t7; sl@0: } sl@0: } {3 345.0} sl@0: sl@0: # Test that if the AUTOINCREMENT is applied to a non integer primary key sl@0: # the error message is sensible. sl@0: do_test autoinc-7.2 { sl@0: catchsql { sl@0: CREATE TABLE t8(x TEXT PRIMARY KEY AUTOINCREMENT); sl@0: } sl@0: } {1 {AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY}} sl@0: sl@0: sl@0: # Ticket #1283. Make sure that preparing but never running a statement sl@0: # that creates the sqlite_sequence table does not mess up the database. sl@0: # sl@0: do_test autoinc-8.1 { sl@0: catch {db2 close} sl@0: catch {db close} sl@0: file delete -force test.db sl@0: sqlite3 db test.db sl@0: set DB [sqlite3_connection_pointer db] sl@0: set STMT [sqlite3_prepare $DB { sl@0: CREATE TABLE t1( sl@0: x INTEGER PRIMARY KEY AUTOINCREMENT sl@0: ) sl@0: } -1 TAIL] sl@0: sqlite3_finalize $STMT sl@0: set STMT [sqlite3_prepare $DB { sl@0: CREATE TABLE t1( sl@0: x INTEGER PRIMARY KEY AUTOINCREMENT sl@0: ) sl@0: } -1 TAIL] sl@0: sqlite3_step $STMT sl@0: sqlite3_finalize $STMT sl@0: execsql { sl@0: INSERT INTO t1 VALUES(NULL); sl@0: SELECT * FROM t1; sl@0: } sl@0: } {1} sl@0: sl@0: # Ticket #3148 sl@0: # Make sure the sqlite_sequence table is not damaged when doing sl@0: # an empty insert - an INSERT INTO ... SELECT ... where the SELECT sl@0: # clause returns an empty set. sl@0: # sl@0: do_test autoinc-9.1 { sl@0: db eval { sl@0: CREATE TABLE t2(x INTEGER PRIMARY KEY AUTOINCREMENT, y); sl@0: INSERT INTO t2 VALUES(NULL, 1); sl@0: CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b); sl@0: INSERT INTO t3 SELECT * FROM t2 WHERE y>1; sl@0: sl@0: SELECT * FROM sqlite_sequence WHERE name='t3'; sl@0: } sl@0: } {t3 0} sl@0: sl@0: sl@0: finish_test