]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Use a intermediate table when inserting a TEMP table from a SELECT that
authordrh <drh@noemail.net>
Thu, 3 Apr 2003 01:50:44 +0000 (01:50 +0000)
committerdrh <drh@noemail.net>
Thu, 3 Apr 2003 01:50:44 +0000 (01:50 +0000)
reads from that same TEMP table.  Ticket #275. (CVS 895)

FossilOrigin-Name: 087d1e83af12b3a9aedd4945f02774a1043b1eb4

manifest
manifest.uuid
src/insert.c
src/vdbe.c
src/vdbe.h
test/insert.test

index f99a0d3469c3aea8a83c5ff130a6daede2189ce9..30dd63c5fe70e501fd21c36cd6f36bdcb9c1d1fe 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sinfrastructure\sto\ssuport\smultiple\sbtree\simplementations\s(CVS\s894)
-D 2003-04-01T21:16:42
+C Use\sa\sintermediate\stable\swhen\sinserting\sa\sTEMP\stable\sfrom\sa\sSELECT\sthat\nreads\sfrom\sthat\ssame\sTEMP\stable.\s\sTicket\s#275.\s(CVS\s895)
+D 2003-04-03T01:50:44
 F Makefile.in 3c4ba24253e61c954d67adbbb4245e7117c5357e
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -29,7 +29,7 @@ F src/expr.c b8daee83f837b24a22d889200bdd74973ca2d8db
 F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605
 F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
-F src/insert.c dad4d914dc729a94e48de171802c23587a62c34f
+F src/insert.c e2f5e7feecb507d904a7da48874595f440b715aa
 F src/main.c 6d9a38491fdc40c041df64a7399244c364481a09
 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
 F src/os.c dfed46091f69cd2d1e601f8a214d41344f2b00b6
@@ -54,8 +54,8 @@ F src/tokenize.c 675b4718d17c69fe7609dc8e85e426ef002be811
 F src/trigger.c bd5a5b234b47f28f9f21a46243dcaf1c5b2383a3
 F src/update.c b368369f1fbe6d7f56a53e5ffad3b75dae9e3e1a
 F src/util.c 8953c612a036e30f24c1c1f5a1498176173daa37
-F src/vdbe.c 7171dbe873760f403b2501e96fd3d1bd852b3ce8
-F src/vdbe.h ed43771f1dc2b994d5c484fdf2eab357c6ef0ee3
+F src/vdbe.c b3b840b555b5238926b7ebb01cd47526a29bb853
+F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
 F src/where.c e5733f7d5e9cc4ed3590dc3401f779e7b7bb8127
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/auth.test 33e8b9680eb0ce521c54096fff1c9ab506c7dfb8
@@ -75,7 +75,7 @@ F test/format3.test 64ab6c4db132b28a645996d413530f7b2a462cc2
 F test/func.test 000515779001ac6899eec4b54e65c6e2501279d4
 F test/in.test 3171a2b3170a8223665c1a4f26be5f3eda36cc4b
 F test/index.test faeb1bcf776e3ff9ba1b4be1eadd1fece708aa7b
-F test/insert.test a122afb86911e77c181d912348866a5b1a61eeab
+F test/insert.test 5697ba098e4d8a6f0151f281b7e39dec9c439e05
 F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
 F test/intpkey.test 39f49fd993350f7f3ab255e5cfbf9a09d8f8800e
 F test/ioerr.test 45c8feebe608d7f456fea27ff27a0aaaf0b9c636
@@ -155,7 +155,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 11378c5bf988412f8564cdc0314fc241793b292e
-R cc8e4c3807eb9ac6929fb512790ca871
-U paul
-Z 048b3196e99f227ca8551c2b49ca1411
+P 79b3aed2a74a67cbad631c4e2e4a43469d80c162
+R 6e7a48442426732645524eccf6cea407
+U drh
+Z b83fa935d7c88982a4c85635851f4582
index 43967b3e83ae652128675f0f0112c8d917cd86e4..534960f4e9abac9763c4746ab75121bc0b6227da 100644 (file)
@@ -1 +1 @@
-79b3aed2a74a67cbad631c4e2e4a43469d80c162
\ No newline at end of file
+087d1e83af12b3a9aedd4945f02774a1043b1eb4
\ No newline at end of file
index 705bd8e9d20c217b9bd7cc6a75b5630d8563c4dc..2e376fa6ac1be8579c5b9f06119c948af9b64e74 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.77 2003/03/31 02:12:47 drh Exp $
+** $Id: insert.c,v 1.78 2003/04/03 01:50:44 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -177,7 +177,6 @@ void sqliteInsert(
     /* Data is coming from a SELECT.  Generate code to implement that SELECT
     */
     int rc, iInitCode;
-    int opCode;
     iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0);
     iSelectLoop = sqliteVdbeCurrentAddr(v);
     iInsertBlock = sqliteVdbeMakeLabel(v);
@@ -191,9 +190,23 @@ void sqliteInsert(
     /* Set useTempTable to TRUE if the result of the SELECT statement
     ** should be written into a temporary table.  Set to FALSE if each
     ** row of the SELECT can be written directly into the result table.
+    **
+    ** A temp table must be used if the table being updated is also one
+    ** of the tables being read by the SELECT statement.  Also use a 
+    ** temp table in the case of row triggers.
     */
-    opCode = pTab->iDb==1 ? OP_OpenTemp : OP_OpenRead;
-    useTempTable = row_triggers_exist || sqliteVdbeFindOp(v,opCode,pTab->tnum);
+    if( row_triggers_exist ){
+      useTempTable = 1;
+    }else{
+      int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum);
+      useTempTable = 0;
+      if( addr>0 ){
+        VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2);
+        if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
+          useTempTable = 1;
+        }
+      }
+    }
 
     if( useTempTable ){
       /* Generate the subroutine that SELECT calls to process each row of
index 8e088b786de6b52ce4109d1bc8bed7765bf823f8..f1c0aa6f8e11e72bd72e93a402f9d3dfcb06b733 100644 (file)
@@ -36,7 +36,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.209 2003/03/20 01:16:59 drh Exp $
+** $Id: vdbe.c,v 1.210 2003/04/03 01:50:45 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -603,17 +603,26 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
 
 /*
 ** Search for the current program for the given opcode and P2
-** value.  Return 1 if found and 0 if not found.
+** value.  Return the address plus 1 if found and 0 if not found.
 */
 int sqliteVdbeFindOp(Vdbe *p, int op, int p2){
   int i;
   assert( p->magic==VDBE_MAGIC_INIT );
   for(i=0; i<p->nOp; i++){
-    if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return 1;
+    if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
   }
   return 0;
 }
 
+/*
+** Return the opcode for a given address.
+*/
+VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){
+  assert( p->magic==VDBE_MAGIC_INIT );
+  assert( addr>=0 && addr<p->nOp );
+  return &p->aOp[addr];
+}
+
 /*
 ** The following group or routines are employed by installable functions
 ** to return their results.
index e66fb3ed9310f4d7dbe55296a7d9abac498ed017..3cdbd7e75309ebb3e4162bc49a96ca7935b8b0c0 100644 (file)
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.64 2003/01/29 18:46:53 drh Exp $
+** $Id: vdbe.h,v 1.65 2003/04/03 01:50:47 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -81,6 +81,7 @@ void sqliteVdbeChangeP2(Vdbe*, int addr, int P2);
 void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
 void sqliteVdbeDequoteP3(Vdbe*, int addr);
 int sqliteVdbeFindOp(Vdbe*, int, int);
+VdbeOp *sqliteVdbeGetOp(Vdbe*, int);
 int sqliteVdbeMakeLabel(Vdbe*);
 void sqliteVdbeDelete(Vdbe*);
 void sqliteVdbeMakeReady(Vdbe*,sqlite_callback,void*,int);
index 7a013a3de37440aebd06e89f056d561bc450470b..f551e4e4ae6b7da48d8e79255942c5a9d6d2834e 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the INSERT statement.
 #
-# $Id: insert.test,v 1.11 2002/06/25 13:16:04 drh Exp $
+# $Id: insert.test,v 1.12 2003/04/03 01:50:48 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -202,6 +202,56 @@ do_test insert-4.7 {
   }
 } {1 3 99}
 
-# Test
+# Test the ability to insert from a temporary table into itself.
+# Ticket #275.
+#
+do_test insert-5.1 {
+  execsql {
+    CREATE TEMP TABLE t4(x);
+    INSERT INTO t4 VALUES(1);
+    SELECT * FROM t4;
+  }
+} {1}
+do_test insert-5.2 {
+  execsql {
+    INSERT INTO t4 SELECT x+1 FROM t4;
+    SELECT * FROM t4;
+  }
+} {1 2}
+do_test insert-5.3 {
+  # verify that a temporary table is used to copy t4 to t4
+  set x [execsql {
+    EXPLAIN INSERT INTO t4 SELECT x+2 FROM t4;
+  }]
+  expr {[lsearch $x OpenTemp]>0}
+} {1}
+do_test insert-5.4 {
+  # Verify that table "test1" begins on page 3.  This should be the same
+  # page number used by "t4" above.
+  execsql {
+    SELECT rootpage FROM sqlite_master WHERE name='test1';
+  }
+} {3}
+do_test insert-5.5 {
+  # Verify that "t4" begins on page 3.
+  execsql {
+    SELECT rootpage FROM sqlite_temp_master WHERE name='t4';
+  }
+} {3}
+do_test insert-5.6 {
+  # This should not use an intermediate temporary table.
+  execsql {
+    INSERT INTO t4 SELECT one FROM test1 WHERE three=7;
+    SELECT * FROM t4
+  }
+} {1 2 8}
+do_test insert-5.7 {
+  # verify that no temporary table is used to copy test1 to t4
+  set x [execsql {
+    EXPLAIN INSERT INTO t4 SELECT one FROM test1;
+  }]
+  expr {[lsearch $x OpenTemp]>0}
+} {0}
+
 
 finish_test