sqlite/test/insert5.test
drh 48d1178ad8 Make sure that INSERT INTO ... SELECT ... always uses an ephemeral
intermediate table if the SELECT clause refers to the destination table,
even if the SELECT clause is compound or uses the destination table
in a subquery.  This fixes a long-standing bug that can cause an
infinite loop for some SQL statements. (CVS 4552)

FossilOrigin-Name: 492b39b6a8bf4ad8792d7a7949f77827a5047fd8
2007-11-23 15:02:19 +00:00

92 lines
2.5 KiB
Plaintext

# 2007 November 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.
#
#***********************************************************************
#
# The tests in this file ensure that a temporary table is used
# when required by an "INSERT INTO ... SELECT ..." statement.
#
# $Id: insert5.test,v 1.1 2007/11/23 15:02:19 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Return true if the compilation of the sql passed as an argument
# includes the opcode OpenEphemeral. An "INSERT INTO ... SELECT"
# statement includes such an opcode if a temp-table is used
# to store intermediate results.
#
proc uses_temp_table {sql} {
return [expr {[lsearch [execsql "EXPLAIN $sql"] OpenEphemeral]>=0}]
}
# Construct the sample database.
#
do_test insert5-1.0 {
file delete -force test2.db test2.db-journal
execsql {
CREATE TABLE MAIN(Id INTEGER, Id1 INTEGER);
CREATE TABLE B(Id INTEGER, Id1 INTEGER);
CREATE VIEW v1 AS SELECT * FROM B;
CREATE VIEW v2 AS SELECT * FROM MAIN;
INSERT INTO MAIN(Id,Id1) VALUES(2,3);
INSERT INTO B(Id,Id1) VALUES(2,3);
}
} {}
# Run the query.
#
do_test insert5-1.1 {
execsql {
INSERT INTO B
SELECT * FROM B UNION ALL
SELECT * FROM MAIN WHERE exists (select * FROM B WHERE B.Id = MAIN.Id);
SELECT * FROM B;
}
} {2 3 2 3 2 3}
do_test insert5-2.1 {
uses_temp_table { INSERT INTO b SELECT * FROM main }
} {0}
do_test insert5-2.2 {
uses_temp_table { INSERT INTO b SELECT * FROM b }
} {1}
do_test insert5-2.3 {
uses_temp_table { INSERT INTO b SELECT (SELECT id FROM b), id1 FROM main }
} {1}
do_test insert5-2.4 {
uses_temp_table { INSERT INTO b SELECT id1, (SELECT id FROM b) FROM main }
} {1}
do_test insert5-2.5 {
uses_temp_table {
INSERT INTO b
SELECT * FROM main WHERE id = (SELECT id1 FROM b WHERE main.id = b.id) }
} {1}
do_test insert5-2.6 {
uses_temp_table { INSERT INTO b SELECT * FROM v1 }
} {1}
do_test insert5-2.7 {
uses_temp_table { INSERT INTO b SELECT * FROM v2 }
} {0}
do_test insert5-2.8 {
uses_temp_table {
INSERT INTO b
SELECT * FROM main WHERE id > 10 AND max(id1, (SELECT id FROM b)) > 10;
}
} {1}
do_test insert5-2.9 {
uses_temp_table {
INSERT INTO b
SELECT * FROM main
WHERE id > 10 AND (SELECT count(*) FROM v2 GROUP BY main.id)
}
} {1}
finish_test