mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Use a intermediate table when inserting a TEMP table from a SELECT that
reads from that same TEMP table. Ticket #275. (CVS 895) FossilOrigin-Name: 087d1e83af12b3a9aedd4945f02774a1043b1eb4
This commit is contained in:
20
manifest
20
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
|
||||
|
@@ -1 +1 @@
|
||||
79b3aed2a74a67cbad631c4e2e4a43469d80c162
|
||||
087d1e83af12b3a9aedd4945f02774a1043b1eb4
|
21
src/insert.c
21
src/insert.c
@@ -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
|
||||
|
15
src/vdbe.c
15
src/vdbe.c
@@ -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.
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user