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