3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
6 # May you do good and not evil.
7 # May you find forgiveness for yourself and forgive others.
8 # May you share freely, never taking more than you give.
10 #***********************************************************************
12 # Requirements testing for WITHOUT ROWID tables.
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
23 # EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
24 # special column, usually called the "rowid", that uniquely identifies
25 # that row within the table.
27 # EVIDENCE-OF: R-32341-39358 However if the phrase "WITHOUT ROWID" is
28 # added to the end of a CREATE TABLE statement, then the special "rowid"
31 do_execsql_test without_rowid5-1.1 {
32 CREATE TABLE t1(a PRIMARY KEY,b,c);
33 CREATE TABLE t1w(a PRIMARY KEY,b,c) WITHOUT ROWID;
34 INSERT INTO t1 VALUES(1565,681,1148),(1429,1190,1619),(425,358,1306);
35 INSERT INTO t1w SELECT a,b,c FROM t1;
36 SELECT rowid, _rowid_, oid FROM t1 ORDER BY a DESC;
38 do_catchsql_test without_rowid5-1.2 {
39 SELECT rowid FROM t1w;
40 } {1 {no such column: rowid}}
41 do_catchsql_test without_rowid5-1.3 {
42 SELECT _rowid_ FROM t1w;
43 } {1 {no such column: _rowid_}}
44 do_catchsql_test without_rowid5-1.4 {
46 } {1 {no such column: oid}}
48 # EVIDENCE-OF: R-00217-01605 To create a WITHOUT ROWID table, simply add
49 # the keywords "WITHOUT ROWID" to the end of the CREATE TABLE statement.
50 # For example: CREATE TABLE IF NOT EXISTS wordcount( word TEXT PRIMARY
51 # KEY, cnt INTEGER ) WITHOUT ROWID;
53 do_execsql_test without_rowid5-2.1 {
54 CREATE TABLE IF NOT EXISTS wordcount(
55 word TEXT PRIMARY KEY,
58 INSERT INTO wordcount VALUES('one',1);
60 do_catchsql_test without_rowid5-2.2 {
61 SELECT rowid FROM wordcount;
62 } {1 {no such column: rowid}}
64 # EVIDENCE-OF: R-24770-17719 As with all SQL syntax, the case of the
65 # keywords does not matter. One can write "WITHOUT rowid" or "without
66 # rowid" or "WiThOuT rOwId" and it will mean the same thing.
68 do_execsql_test without_rowid5-2.3 {
69 CREATE TABLE IF NOT EXISTS wordcount_b(
70 word TEXT PRIMARY KEY,
73 INSERT INTO wordcount_b VALUES('one',1);
75 do_catchsql_test without_rowid5-2.4 {
76 SELECT rowid FROM wordcount_b;
77 } {1 {no such column: rowid}}
78 do_execsql_test without_rowid5-2.5 {
79 CREATE TABLE IF NOT EXISTS wordcount_c(
80 word TEXT PRIMARY KEY,
83 INSERT INTO wordcount_c VALUES('one',1);
85 do_catchsql_test without_rowid5-2.6 {
86 SELECT rowid FROM wordcount_c;
87 } {1 {no such column: rowid}}
88 do_execsql_test without_rowid5-2.7 {
89 CREATE TABLE IF NOT EXISTS wordcount_d(
90 word TEXT PRIMARY KEY,
93 INSERT INTO wordcount_d VALUES('one',1);
95 do_catchsql_test without_rowid5-2.8 {
96 SELECT rowid FROM wordcount_d;
97 } {1 {no such column: rowid}}
99 # EVIDENCE-OF: R-01418-51310 However, only "rowid" works as the keyword
100 # in the CREATE TABLE statement.
102 do_catchsql_test without_rowid5-3.1 {
103 CREATE TABLE IF NOT EXISTS error1(
104 word TEXT PRIMARY KEY,
107 } {1 {unknown table option: _rowid_}}
108 do_catchsql_test without_rowid5-3.2 {
109 CREATE TABLE IF NOT EXISTS error2(
110 word TEXT PRIMARY KEY,
113 } {1 {unknown table option: oid}}
115 # EVIDENCE-OF: R-58033-17334 An error is raised if a CREATE TABLE
116 # statement with the WITHOUT ROWID clause lacks a PRIMARY KEY.
118 # EVIDENCE-OF: R-63443-09418 Every WITHOUT ROWID table must have a
121 # EVIDENCE-OF: R-27966-31616 An attempt to create a WITHOUT ROWID table
122 # without a PRIMARY KEY results in an error.
124 do_catchsql_test without_rowid5-4.1 {
125 CREATE TABLE IF NOT EXISTS error3(
129 } {1 {PRIMARY KEY missing on table error3}}
131 # EVIDENCE-OF: R-48230-36247 The special behaviors associated "INTEGER
132 # PRIMARY KEY" do not apply on WITHOUT ROWID tables.
134 do_execsql_test without_rowid5-5.1 {
135 CREATE TABLE ipk(key INTEGER PRIMARY KEY, val TEXT) WITHOUT ROWID;
136 INSERT INTO ipk VALUES('rival','bonus'); -- ok to insert non-integer key
139 do_catchsql_test without_rowid5-5.2a {
141 INSERT INTO ipk VALUES(NULL,'sample'); -- no automatic generation of keys
142 } {1 {NOT NULL constraint failed: ipk.key}}
143 do_execsql_test without_rowid5-5.2b {
147 # EVIDENCE-OF: R-33142-02092 AUTOINCREMENT does not work on WITHOUT
150 # EVIDENCE-OF: R-53084-07740 An error is raised if the "AUTOINCREMENT"
151 # keyword is used in the CREATE TABLE statement for a WITHOUT ROWID
154 do_catchsql_test without_rowid5-5.3 {
155 CREATE TABLE ipk2(key INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)WITHOUT ROWID;
156 } {1 {AUTOINCREMENT not allowed on WITHOUT ROWID tables}}
158 # EVIDENCE-OF: R-27831-00579 NOT NULL is enforced on every column of the
159 # PRIMARY KEY in a WITHOUT ROWID table.
161 # EVIDENCE-OF: R-29781-51289 So, ordinary rowid tables in SQLite violate
162 # the SQL standard and allow NULL values in PRIMARY KEY fields.
164 # EVIDENCE-OF: R-27472-62612 But WITHOUT ROWID tables do follow the
165 # standard and will throw an error on any attempt to insert a NULL into
166 # a PRIMARY KEY column.
168 do_execsql_test without_rowid5-5.4 {
169 CREATE TABLE nn(a, b, c, d, e, PRIMARY KEY(c,a,e));
170 CREATE TABLE nnw(a, b, c, d, e, PRIMARY KEY(c,a,e)) WITHOUT ROWID;
171 INSERT INTO nn VALUES(1,2,3,4,5);
172 INSERT INTO nnw VALUES(1,2,3,4,5);
174 do_execsql_test without_rowid5-5.5 {
175 INSERT INTO nn VALUES(NULL, 3,4,5,6);
176 INSERT INTO nn VALUES(3,4,NULL,7,8);
177 INSERT INTO nn VALUES(4,5,6,7,NULL);
178 SELECT count(*) FROM nn;
180 do_catchsql_test without_rowid5-5.6 {
181 INSERT INTO nnw VALUES(NULL, 3,4,5,6);
182 } {1 {NOT NULL constraint failed: nnw.a}}
183 do_catchsql_test without_rowid5-5.7 {
184 INSERT INTO nnw VALUES(3,4,NULL,7,8)
185 } {1 {NOT NULL constraint failed: nnw.c}}
186 do_catchsql_test without_rowid5-5.8 {
187 INSERT INTO nnw VALUES(4,5,6,7,NULL)
188 } {1 {NOT NULL constraint failed: nnw.e}}
189 do_execsql_test without_rowid5-5.9 {
190 SELECT count(*) FROM nnw;
193 # Ticket f2be158c57aaa8c6 (2021-08-18)
194 # NOT NULL ON CONFLICT clauses work on WITHOUT ROWID tables now.
196 do_test without_rowid5-5.100 {
198 DROP TABLE IF EXISTS t5;
200 a INT NOT NULL ON CONFLICT ROLLBACK,
206 INSERT INTO t5(a,b,c) VALUES(1,2,3);
208 catch {db eval {INSERT INTO t5(a,b,c) VALUES(NULL,6,7);}}
213 do_test without_rowid5-5.101 {
215 DROP TABLE IF EXISTS t5;
217 a INT NOT NULL ON CONFLICT ABORT,
223 INSERT INTO t5(a,b,c) VALUES(1,2,3);
225 catch {db eval {INSERT INTO t5(a,b,c) VALUES(NULL,6,7);}}
231 do_test without_rowid5-5.102 {
233 DROP TABLE IF EXISTS t5;
235 a INT NOT NULL ON CONFLICT FAIL,
241 catch {db eval {INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8);}}
246 do_test without_rowid5-5.103 {
248 DROP TABLE IF EXISTS t5;
250 a INT NOT NULL ON CONFLICT IGNORE,
255 INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8);
259 do_test without_rowid5-5.104 {
261 DROP TABLE IF EXISTS t5;
263 a INT NOT NULL ON CONFLICT REPLACE DEFAULT 3,
268 INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8);
271 } {1 2 3 3 4 5 6 7 8}
274 # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not
275 # work for WITHOUT ROWID tables.
277 # EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table
279 do_execsql_test without_rowid5-6.1 {
280 CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID;
281 INSERT INTO b1 VALUES(1,x'0102030405060708090a0b0c0d0e0f');
283 do_test without_rowid5-6.2 {
284 set rc [catch {db incrblob b1 b 1} msg]
286 } {1 {cannot open table without rowid: b1}}