sl@0
|
1 |
# 2007 January 24
|
sl@0
|
2 |
#
|
sl@0
|
3 |
# The author disclaims copyright to this source code. In place of
|
sl@0
|
4 |
# a legal notice, here is a blessing:
|
sl@0
|
5 |
#
|
sl@0
|
6 |
# May you do good and not evil.
|
sl@0
|
7 |
# May you find forgiveness for yourself and forgive others.
|
sl@0
|
8 |
# May you share freely, never taking more than you give.
|
sl@0
|
9 |
#
|
sl@0
|
10 |
#***********************************************************************
|
sl@0
|
11 |
# This file implements regression tests for SQLite library. The
|
sl@0
|
12 |
# focus of this file is testing the INSERT transfer optimization.
|
sl@0
|
13 |
#
|
sl@0
|
14 |
# $Id: insert4.test,v 1.10 2008/01/21 16:22:46 drh Exp $
|
sl@0
|
15 |
|
sl@0
|
16 |
set testdir [file dirname $argv0]
|
sl@0
|
17 |
source $testdir/tester.tcl
|
sl@0
|
18 |
|
sl@0
|
19 |
ifcapable !view||!subquery {
|
sl@0
|
20 |
finish_test
|
sl@0
|
21 |
return
|
sl@0
|
22 |
}
|
sl@0
|
23 |
|
sl@0
|
24 |
# The sqlite3_xferopt_count variable is incremented whenever the
|
sl@0
|
25 |
# insert transfer optimization applies.
|
sl@0
|
26 |
#
|
sl@0
|
27 |
# This procedure runs a test to see if the sqlite3_xferopt_count is
|
sl@0
|
28 |
# set to N.
|
sl@0
|
29 |
#
|
sl@0
|
30 |
proc xferopt_test {testname N} {
|
sl@0
|
31 |
do_test $testname {set ::sqlite3_xferopt_count} $N
|
sl@0
|
32 |
}
|
sl@0
|
33 |
|
sl@0
|
34 |
# Create tables used for testing.
|
sl@0
|
35 |
#
|
sl@0
|
36 |
execsql {
|
sl@0
|
37 |
PRAGMA legacy_file_format = 0;
|
sl@0
|
38 |
CREATE TABLE t1(a int, b int, check(b>a));
|
sl@0
|
39 |
CREATE TABLE t2(x int, y int);
|
sl@0
|
40 |
CREATE VIEW v2 AS SELECT y, x FROM t2;
|
sl@0
|
41 |
CREATE TABLE t3(a int, b int);
|
sl@0
|
42 |
}
|
sl@0
|
43 |
|
sl@0
|
44 |
# Ticket #2252. Make sure the an INSERT from identical tables
|
sl@0
|
45 |
# does not violate constraints.
|
sl@0
|
46 |
#
|
sl@0
|
47 |
do_test insert4-1.1 {
|
sl@0
|
48 |
set sqlite3_xferopt_count 0
|
sl@0
|
49 |
execsql {
|
sl@0
|
50 |
DELETE FROM t1;
|
sl@0
|
51 |
DELETE FROM t2;
|
sl@0
|
52 |
INSERT INTO t2 VALUES(9,1);
|
sl@0
|
53 |
}
|
sl@0
|
54 |
catchsql {
|
sl@0
|
55 |
INSERT INTO t1 SELECT * FROM t2;
|
sl@0
|
56 |
}
|
sl@0
|
57 |
} {1 {constraint failed}}
|
sl@0
|
58 |
xferopt_test insert4-1.2 0
|
sl@0
|
59 |
do_test insert4-1.3 {
|
sl@0
|
60 |
execsql {
|
sl@0
|
61 |
SELECT * FROM t1;
|
sl@0
|
62 |
}
|
sl@0
|
63 |
} {}
|
sl@0
|
64 |
|
sl@0
|
65 |
# Tests to make sure that the transfer optimization is not occurring
|
sl@0
|
66 |
# when it is not a valid optimization.
|
sl@0
|
67 |
#
|
sl@0
|
68 |
# The SELECT must be against a real table.
|
sl@0
|
69 |
do_test insert4-2.1.1 {
|
sl@0
|
70 |
execsql {
|
sl@0
|
71 |
DELETE FROM t1;
|
sl@0
|
72 |
INSERT INTO t1 SELECT 4, 8;
|
sl@0
|
73 |
SELECT * FROM t1;
|
sl@0
|
74 |
}
|
sl@0
|
75 |
} {4 8}
|
sl@0
|
76 |
xferopt_test insert4-2.1.2 0
|
sl@0
|
77 |
do_test insert4-2.2.1 {
|
sl@0
|
78 |
catchsql {
|
sl@0
|
79 |
DELETE FROM t1;
|
sl@0
|
80 |
INSERT INTO t1 SELECT * FROM v2;
|
sl@0
|
81 |
SELECT * FROM t1;
|
sl@0
|
82 |
}
|
sl@0
|
83 |
} {0 {1 9}}
|
sl@0
|
84 |
xferopt_test insert4-2.2.2 0
|
sl@0
|
85 |
|
sl@0
|
86 |
# Do not run the transfer optimization if there is a LIMIT clause
|
sl@0
|
87 |
#
|
sl@0
|
88 |
do_test insert4-2.3.1 {
|
sl@0
|
89 |
execsql {
|
sl@0
|
90 |
DELETE FROM t2;
|
sl@0
|
91 |
INSERT INTO t2 VALUES(9,1);
|
sl@0
|
92 |
INSERT INTO t2 SELECT y, x FROM t2;
|
sl@0
|
93 |
INSERT INTO t3 SELECT * FROM t2 LIMIT 1;
|
sl@0
|
94 |
SELECT * FROM t3;
|
sl@0
|
95 |
}
|
sl@0
|
96 |
} {9 1}
|
sl@0
|
97 |
xferopt_test insert4-2.3.2 0
|
sl@0
|
98 |
do_test insert4-2.3.3 {
|
sl@0
|
99 |
catchsql {
|
sl@0
|
100 |
DELETE FROM t1;
|
sl@0
|
101 |
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
|
sl@0
|
102 |
SELECT * FROM t1;
|
sl@0
|
103 |
}
|
sl@0
|
104 |
} {1 {constraint failed}}
|
sl@0
|
105 |
xferopt_test insert4-2.3.4 0
|
sl@0
|
106 |
|
sl@0
|
107 |
# Do not run the transfer optimization if there is a DISTINCT
|
sl@0
|
108 |
#
|
sl@0
|
109 |
do_test insert4-2.4.1 {
|
sl@0
|
110 |
execsql {
|
sl@0
|
111 |
DELETE FROM t3;
|
sl@0
|
112 |
INSERT INTO t3 SELECT DISTINCT * FROM t2;
|
sl@0
|
113 |
SELECT * FROM t3;
|
sl@0
|
114 |
}
|
sl@0
|
115 |
} {1 9 9 1}
|
sl@0
|
116 |
xferopt_test insert4-2.4.2 0
|
sl@0
|
117 |
do_test insert4-2.4.3 {
|
sl@0
|
118 |
catchsql {
|
sl@0
|
119 |
DELETE FROM t1;
|
sl@0
|
120 |
INSERT INTO t1 SELECT DISTINCT * FROM t2;
|
sl@0
|
121 |
}
|
sl@0
|
122 |
} {1 {constraint failed}}
|
sl@0
|
123 |
xferopt_test insert4-2.4.4 0
|
sl@0
|
124 |
|
sl@0
|
125 |
# The following procedure constructs two tables then tries to transfer
|
sl@0
|
126 |
# data from one table to the other. Checks are made to make sure the
|
sl@0
|
127 |
# transfer is successful and that the transfer optimization was used or
|
sl@0
|
128 |
# not, as appropriate.
|
sl@0
|
129 |
#
|
sl@0
|
130 |
# xfer_check TESTID XFER-USED INIT-DATA DEST-SCHEMA SRC-SCHEMA
|
sl@0
|
131 |
#
|
sl@0
|
132 |
# The TESTID argument is the symbolic name for this test. The XFER-USED
|
sl@0
|
133 |
# argument is true if the transfer optimization should be employed and
|
sl@0
|
134 |
# false if not. INIT-DATA is a single row of data that is to be
|
sl@0
|
135 |
# transfered. DEST-SCHEMA and SRC-SCHEMA are table declarations for
|
sl@0
|
136 |
# the destination and source tables.
|
sl@0
|
137 |
#
|
sl@0
|
138 |
proc xfer_check {testid xferused initdata destschema srcschema} {
|
sl@0
|
139 |
execsql "CREATE TABLE dest($destschema)"
|
sl@0
|
140 |
execsql "CREATE TABLE src($srcschema)"
|
sl@0
|
141 |
execsql "INSERT INTO src VALUES([join $initdata ,])"
|
sl@0
|
142 |
set ::sqlite3_xferopt_count 0
|
sl@0
|
143 |
do_test $testid.1 {
|
sl@0
|
144 |
execsql {
|
sl@0
|
145 |
INSERT INTO dest SELECT * FROM src;
|
sl@0
|
146 |
SELECT * FROM dest;
|
sl@0
|
147 |
}
|
sl@0
|
148 |
} $initdata
|
sl@0
|
149 |
do_test $testid.2 {
|
sl@0
|
150 |
set ::sqlite3_xferopt_count
|
sl@0
|
151 |
} $xferused
|
sl@0
|
152 |
execsql {
|
sl@0
|
153 |
DROP TABLE dest;
|
sl@0
|
154 |
DROP TABLE src;
|
sl@0
|
155 |
}
|
sl@0
|
156 |
}
|
sl@0
|
157 |
|
sl@0
|
158 |
|
sl@0
|
159 |
# Do run the transfer optimization if tables have identical
|
sl@0
|
160 |
# CHECK constraints.
|
sl@0
|
161 |
#
|
sl@0
|
162 |
xfer_check insert4-3.1 1 {1 9} \
|
sl@0
|
163 |
{a int, b int CHECK(b>a)} \
|
sl@0
|
164 |
{x int, y int CHECK(y>x)}
|
sl@0
|
165 |
xfer_check insert4-3.2 1 {1 9} \
|
sl@0
|
166 |
{a int, b int CHECK(b>a)} \
|
sl@0
|
167 |
{x int CHECK(y>x), y int}
|
sl@0
|
168 |
|
sl@0
|
169 |
# Do run the transfer optimization if the destination table lacks
|
sl@0
|
170 |
# any CHECK constraints regardless of whether or not there are CHECK
|
sl@0
|
171 |
# constraints on the source table.
|
sl@0
|
172 |
#
|
sl@0
|
173 |
xfer_check insert4-3.3 1 {1 9} \
|
sl@0
|
174 |
{a int, b int} \
|
sl@0
|
175 |
{x int, y int CHECK(y>x)}
|
sl@0
|
176 |
|
sl@0
|
177 |
# Do run the transfer optimization if the destination table omits
|
sl@0
|
178 |
# NOT NULL constraints that the source table has.
|
sl@0
|
179 |
#
|
sl@0
|
180 |
xfer_check insert4-3.4 0 {1 9} \
|
sl@0
|
181 |
{a int, b int CHECK(b>a)} \
|
sl@0
|
182 |
{x int, y int}
|
sl@0
|
183 |
|
sl@0
|
184 |
# Do not run the optimization if the destination has NOT NULL
|
sl@0
|
185 |
# constraints that the source table lacks.
|
sl@0
|
186 |
#
|
sl@0
|
187 |
xfer_check insert4-3.5 0 {1 9} \
|
sl@0
|
188 |
{a int, b int NOT NULL} \
|
sl@0
|
189 |
{x int, y int}
|
sl@0
|
190 |
xfer_check insert4-3.6 0 {1 9} \
|
sl@0
|
191 |
{a int, b int NOT NULL} \
|
sl@0
|
192 |
{x int NOT NULL, y int}
|
sl@0
|
193 |
xfer_check insert4-3.7 0 {1 9} \
|
sl@0
|
194 |
{a int NOT NULL, b int NOT NULL} \
|
sl@0
|
195 |
{x int NOT NULL, y int}
|
sl@0
|
196 |
xfer_check insert4-3.8 0 {1 9} \
|
sl@0
|
197 |
{a int NOT NULL, b int} \
|
sl@0
|
198 |
{x int, y int}
|
sl@0
|
199 |
|
sl@0
|
200 |
|
sl@0
|
201 |
# Do run the transfer optimization if the destination table and
|
sl@0
|
202 |
# source table have the same NOT NULL constraints or if the
|
sl@0
|
203 |
# source table has extra NOT NULL constraints.
|
sl@0
|
204 |
#
|
sl@0
|
205 |
xfer_check insert4-3.9 1 {1 9} \
|
sl@0
|
206 |
{a int, b int} \
|
sl@0
|
207 |
{x int NOT NULL, y int}
|
sl@0
|
208 |
xfer_check insert4-3.10 1 {1 9} \
|
sl@0
|
209 |
{a int, b int} \
|
sl@0
|
210 |
{x int NOT NULL, y int NOT NULL}
|
sl@0
|
211 |
xfer_check insert4-3.11 1 {1 9} \
|
sl@0
|
212 |
{a int NOT NULL, b int} \
|
sl@0
|
213 |
{x int NOT NULL, y int NOT NULL}
|
sl@0
|
214 |
xfer_check insert4-3.12 1 {1 9} \
|
sl@0
|
215 |
{a int, b int NOT NULL} \
|
sl@0
|
216 |
{x int NOT NULL, y int NOT NULL}
|
sl@0
|
217 |
|
sl@0
|
218 |
# Do not run the optimization if any corresponding table
|
sl@0
|
219 |
# columns have different affinities.
|
sl@0
|
220 |
#
|
sl@0
|
221 |
xfer_check insert4-3.20 0 {1 9} \
|
sl@0
|
222 |
{a text, b int} \
|
sl@0
|
223 |
{x int, b int}
|
sl@0
|
224 |
xfer_check insert4-3.21 0 {1 9} \
|
sl@0
|
225 |
{a int, b int} \
|
sl@0
|
226 |
{x text, b int}
|
sl@0
|
227 |
|
sl@0
|
228 |
# "int" and "integer" are equivalent so the optimization should
|
sl@0
|
229 |
# run here.
|
sl@0
|
230 |
#
|
sl@0
|
231 |
xfer_check insert4-3.22 1 {1 9} \
|
sl@0
|
232 |
{a int, b int} \
|
sl@0
|
233 |
{x integer, b int}
|
sl@0
|
234 |
|
sl@0
|
235 |
# Ticket #2291.
|
sl@0
|
236 |
#
|
sl@0
|
237 |
|
sl@0
|
238 |
do_test insert4-4.1a {
|
sl@0
|
239 |
execsql {CREATE TABLE t4(a, b, UNIQUE(a,b))}
|
sl@0
|
240 |
} {}
|
sl@0
|
241 |
ifcapable vacuum {
|
sl@0
|
242 |
do_test insert4-4.1b {
|
sl@0
|
243 |
execsql {
|
sl@0
|
244 |
INSERT INTO t4 VALUES(NULL,0);
|
sl@0
|
245 |
INSERT INTO t4 VALUES(NULL,1);
|
sl@0
|
246 |
INSERT INTO t4 VALUES(NULL,1);
|
sl@0
|
247 |
VACUUM;
|
sl@0
|
248 |
}
|
sl@0
|
249 |
} {}
|
sl@0
|
250 |
}
|
sl@0
|
251 |
|
sl@0
|
252 |
# Check some error conditions:
|
sl@0
|
253 |
#
|
sl@0
|
254 |
do_test insert4-5.1 {
|
sl@0
|
255 |
# Table does not exist.
|
sl@0
|
256 |
catchsql { INSERT INTO t2 SELECT * FROM nosuchtable }
|
sl@0
|
257 |
} {1 {no such table: nosuchtable}}
|
sl@0
|
258 |
do_test insert4-5.2 {
|
sl@0
|
259 |
# Number of columns does not match.
|
sl@0
|
260 |
catchsql {
|
sl@0
|
261 |
CREATE TABLE t5(a, b, c);
|
sl@0
|
262 |
INSERT INTO t4 SELECT * FROM t5;
|
sl@0
|
263 |
}
|
sl@0
|
264 |
} {1 {table t4 has 2 columns but 3 values were supplied}}
|
sl@0
|
265 |
|
sl@0
|
266 |
do_test insert4-6.1 {
|
sl@0
|
267 |
set ::sqlite3_xferopt_count 0
|
sl@0
|
268 |
execsql {
|
sl@0
|
269 |
CREATE INDEX t2_i2 ON t2(x, y COLLATE nocase);
|
sl@0
|
270 |
CREATE INDEX t2_i1 ON t2(x ASC, y DESC);
|
sl@0
|
271 |
CREATE INDEX t3_i1 ON t3(a, b);
|
sl@0
|
272 |
INSERT INTO t2 SELECT * FROM t3;
|
sl@0
|
273 |
}
|
sl@0
|
274 |
set ::sqlite3_xferopt_count
|
sl@0
|
275 |
} {0}
|
sl@0
|
276 |
do_test insert4-6.2 {
|
sl@0
|
277 |
set ::sqlite3_xferopt_count 0
|
sl@0
|
278 |
execsql {
|
sl@0
|
279 |
DROP INDEX t2_i2;
|
sl@0
|
280 |
INSERT INTO t2 SELECT * FROM t3;
|
sl@0
|
281 |
}
|
sl@0
|
282 |
set ::sqlite3_xferopt_count
|
sl@0
|
283 |
} {0}
|
sl@0
|
284 |
do_test insert4-6.3 {
|
sl@0
|
285 |
set ::sqlite3_xferopt_count 0
|
sl@0
|
286 |
execsql {
|
sl@0
|
287 |
DROP INDEX t2_i1;
|
sl@0
|
288 |
CREATE INDEX t2_i1 ON t2(x ASC, y ASC);
|
sl@0
|
289 |
INSERT INTO t2 SELECT * FROM t3;
|
sl@0
|
290 |
}
|
sl@0
|
291 |
set ::sqlite3_xferopt_count
|
sl@0
|
292 |
} {1}
|
sl@0
|
293 |
do_test insert4-6.4 {
|
sl@0
|
294 |
set ::sqlite3_xferopt_count 0
|
sl@0
|
295 |
execsql {
|
sl@0
|
296 |
DROP INDEX t2_i1;
|
sl@0
|
297 |
CREATE INDEX t2_i1 ON t2(x ASC, y COLLATE RTRIM);
|
sl@0
|
298 |
INSERT INTO t2 SELECT * FROM t3;
|
sl@0
|
299 |
}
|
sl@0
|
300 |
set ::sqlite3_xferopt_count
|
sl@0
|
301 |
} {0}
|
sl@0
|
302 |
|
sl@0
|
303 |
|
sl@0
|
304 |
|
sl@0
|
305 |
|
sl@0
|
306 |
finish_test
|