Enhancements to the DELETE command (CVS 194)

FossilOrigin-Name: daea156e2430762e683ff5460f9f8bb3204ae168
This commit is contained in:
drh 2001-03-20 22:05:00 +00:00
parent 8721f00485
commit 0353cedda4
12 changed files with 211 additions and 236 deletions

View File

@ -1 +1 @@
1.0.26
1.0.27

View File

@ -1,20 +1,20 @@
C Version\s1.0.26\s(CVS\s477)
D 2001-03-20T13:00:00
C Enhancements\sto\sthe\sDELETE\scommand\s(CVS\s194)
D 2001-03-20T22:05:00
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 7efa81e2985b45ba73db27d55b70cc927f5abfd7
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
F VERSION 900bbde4128ea2f66efdd32cae849187ea790e77
F VERSION dee81fa1259d8cbb43230e982a9392f11f89859d
F configure 3dc1edb9dcf60215e31ff72b447935ab62211442 x
F configure.in d892ca33db7e88a055519ce2f36dcb11020e8fff
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
F src/build.c 7aa5879bf58ea6bbff22c26c59d1130021fa6ca4
F src/dbbe.c 1b3b8b5ded9e58d10d94d268cd12343b6212dbd1
F src/dbbe.h 0435a36906a839cce062608f51bd9d3e79878fec
F src/dbbegdbm.c 5bfcb1b4ee47a98c5eae83041e9716cd3233fd0e
F src/dbbemem.c e0ffaae47c22dd8d73362a4fae2f2b4f074fd079
F src/delete.c b83dc815f83220a82df13f1f1f479187d305fe6a
F src/dbbe.c b178f0959f6bac5ef8a109484c1571053f31abe5
F src/dbbe.h 57d6debb99f6d7a91364b73cf3f0b129058ebbb3
F src/dbbegdbm.c 84b2bf31d220f1de1cb0507ea051d30128fd681b
F src/dbbemem.c d0fb86f1e8a52cdb195dc91d07f43765cf48bb95
F src/delete.c 7aa9dcb86d5e98c3eb9dee00a459e0ef9b73fbe3
F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a
F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7
F src/ex/db.h 3f2933ee20c147fe494835786e4c6f3a562def4e
@ -33,20 +33,20 @@ F src/select.c faac634ef0c717bc82ca112a4531a257886f2c7a
F src/shell.c 441e20913cde0bb71281f4027623c623530241cd
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 7c1a53f020418d89d13ed2fe9c477ff54540755d
F src/sqliteInt.h fd513fa6b7ac94919f85ebfa183aaa194284ce16
F src/sqliteInt.h 9887d207b98362392668410a11c59b3e334f51a1
F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9
F src/tclsqlite.c 2a925e1835c348f07dd17c87d95ae9a577833407
F src/test.file 55ca6286e3e4f4fba5d0448333fa99fc5a404a73
F src/tokenize.c c7ad428f38e56342eb2025320480b5ae9ece1b90
F src/update.c 8365b3922ea098330d1e20862d6e64911e4e03d0
F src/util.c f4573201fc2b581dbf601c53787349310b7da150
F src/vdbe.c e8254ae39d2f42a3f85b168b67a493ae206f4bf4
F src/vdbe.c aa14a8aef0229fd5cfa32c3957dc627555f42be8
F src/vdbe.h 031b7dd7d6f94c51dc37cdf26efe43d1619bb672
F src/where.c 478fde7c930969ca428de2d80b137959d25ee2fb
F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
F test/dbbe.test 03a6940807f8a1e7538897b4c802a7937677e053
F test/delete.test e3e082a9dc764e3c259a8d175b31cd648e7c58f7
F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
F test/expr.test 48273bf48a15d226c35829f702af4254c0ff6795
F test/func.test 02aed8845b98bde1043dda97455de1d37238ebb3
F test/in.test 2c560c0f55fb777029fd9bb5378f2997582aa603
@ -80,7 +80,7 @@ F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8
F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6
F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
F www/c_interface.tcl 11be2d5826eb7d6efd629751d3b483c1ed78ba14
F www/changes.tcl 6216d3a09f4cde137e635ab9aedda63adef086c0
F www/changes.tcl e01a5257038fafe0302b629d1b278789409029d2
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
@ -91,7 +91,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
P 126fbcb7a8f52a0cc01c8346150a187dbabe96d5
R daa25a3d54c3808b11e465e636487674
P 99f9ea412f87cfb518cfb34f0e187fd1baf56761
R e053fcd301655951022cbe2ddba947b1
U drh
Z a8bc1022041cda3a4a5da0367e128d28
Z 61cc14fc5b8ff57148f02f9ffc944cce

View File

@ -1 +1 @@
99f9ea412f87cfb518cfb34f0e187fd1baf56761
daea156e2430762e683ff5460f9f8bb3204ae168

View File

@ -30,7 +30,7 @@
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.24 2001/03/20 12:55:14 drh Exp $
** $Id: dbbe.c,v 1.25 2001/03/20 22:05:00 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
@ -64,92 +64,6 @@ Dbbe *sqliteDbbeOpen(
return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg);
}
/*
** Open a temporary file. The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file. That works great
** under Unix, but fails when we try to port to Windows.
*/
int sqliteDbbeOpenTempFile(const char *zDir, Dbbe *pBe, FILE **ppFile){
char *zFile; /* Full name of the temporary file */
char zBuf[50]; /* Base name of the temporary file */
int i; /* Loop counter */
int limit; /* Prevent an infinite loop */
int rc = SQLITE_OK; /* Value returned by this function */
for(i=0; i<pBe->nTemp; i++){
if( pBe->apTemp[i]==0 ) break;
}
if( i>=pBe->nTemp ){
pBe->nTemp++;
pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
pBe->azTemp = sqliteRealloc(pBe->azTemp, pBe->nTemp*sizeof(char*) );
}
if( pBe->apTemp==0 ){
*ppFile = 0;
return SQLITE_NOMEM;
}
limit = 4;
zFile = 0;
do{
sqliteRandomName(zBuf, "/_temp_file_");
sqliteFree(zFile);
zFile = 0;
sqliteSetString(&zFile, zDir, zBuf, 0);
}while( access(zFile,0)==0 && limit-- >= 0 );
#if OS_WIN
*ppFile = pBe->apTemp[i] = fopen(zFile, "w+b");
#else
*ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
#endif
if( pBe->apTemp[i]==0 ){
rc = SQLITE_ERROR;
sqliteFree(zFile);
pBe->azTemp[i] = 0;
}else{
pBe->azTemp[i] = zFile;
}
return rc;
}
/*
** Close a temporary file opened using sqliteGdbmOpenTempFile()
*/
void sqliteDbbeCloseTempFile(Dbbe *pBe, FILE *f){
int i;
for(i=0; i<pBe->nTemp; i++){
if( pBe->apTemp[i]==f ){
unlink(pBe->azTemp[i]);
sqliteFree(pBe->azTemp[i]);
pBe->apTemp[i] = 0;
pBe->azTemp[i] = 0;
break;
}
}
fclose(f);
}
/*
** Close all temporary files that happen to still be open.
** This routine is called when the database is being closed.
*/
void sqliteDbbeCloseAllTempFiles(Dbbe *pBe){
int i;
for(i=0; i<pBe->nTemp; i++){
if( pBe->apTemp[i]!=0 ){
unlink(pBe->azTemp[i]);
fclose(pBe->apTemp[i]);
sqliteFree(pBe->azTemp[i]);
pBe->apTemp[i] = 0;
pBe->azTemp[i] = 0;
break;
}
}
sqliteFree(pBe->azTemp);
sqliteFree(pBe->apTemp);
}
/*
** Translate the name of an SQL table (or index) into the name
** of a file that holds the key/data pairs for that table or

View File

@ -28,7 +28,7 @@
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
** $Id: dbbe.h,v 1.10 2001/01/15 22:51:10 drh Exp $
** $Id: dbbe.h,v 1.11 2001/03/20 22:05:00 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
@ -150,12 +150,6 @@ struct DbbeMethods {
/* Remove an entry from the table */
int (*Delete)(DbbeCursor*, int nKey, char *pKey);
/* Open a file suitable for temporary storage */
int (*OpenTempFile)(Dbbe*, FILE**);
/* Close a temporary file */
void (*CloseTempFile)(Dbbe *, FILE *);
};
/*
@ -170,9 +164,8 @@ struct DbbeMethods {
*/
struct Dbbe {
struct DbbeMethods *x; /* Backend-specific methods for database access */
int nTemp; /* Number of temporary files created */
FILE **apTemp; /* Space to hold temporary file pointers */
char **azTemp; /* Names of the temporary files */
/* There used to be other information here, but it has since
** been removed. */
};
#endif /* defined(_SQLITE_DBBE_H_) */

View File

@ -30,7 +30,7 @@
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbegdbm.c,v 1.3 2001/01/15 22:51:10 drh Exp $
** $Id: dbbegdbm.c,v 1.4 2001/03/20 22:05:00 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
@ -110,7 +110,6 @@ static void sqliteGdbmClose(Dbbe *pDbbe){
memset(pFile, 0, sizeof(*pFile));
sqliteFree(pFile);
}
sqliteDbbeCloseAllTempFiles(pDbbe);
memset(pBe, 0, sizeof(*pBe));
sqliteFree(pBe);
}
@ -541,15 +540,6 @@ static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){
return rc;
}
/*
** Open a temporary file. The file is located in the same directory
** as the rest of the database.
*/
static int sqliteGdbmOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
Dbbex *pBe = (Dbbex*)pDbbe;
return sqliteDbbeOpenTempFile(pBe->zDir, pDbbe, ppFile);
}
/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.
@ -573,8 +563,6 @@ static struct DbbeMethods gdbmMethods = {
/* New */ sqliteGdbmNew,
/* Put */ sqliteGdbmPut,
/* Delete */ sqliteGdbmDelete,
/* OpenTempFile */ sqliteGdbmOpenTempFile,
/* CloseTempFile */ sqliteDbbeCloseTempFile
};

View File

@ -28,7 +28,7 @@
**
** This file uses an in-memory hash table as the database backend.
**
** $Id: dbbemem.c,v 1.10 2001/03/20 12:57:57 drh Exp $
** $Id: dbbemem.c,v 1.11 2001/03/20 22:05:00 drh Exp $
*/
#include "sqliteInt.h"
#include <sys/stat.h>
@ -399,7 +399,6 @@ static void sqliteMemClose(Dbbe *pDbbe){
deleteMTable(pTble);
}
ArrayClear(&pBe->tables);
sqliteDbbeCloseAllTempFiles(pDbbe);
memset(pBe, 0, sizeof(*pBe));
sqliteFree(pBe);
}
@ -716,31 +715,6 @@ static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){
return SQLITE_OK;
}
/*
** Open a temporary file. The file is located in the current working
** directory.
*/
static int sqliteMemOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
#if OS_UNIX
const char *zTemps[] = { "/usr/tmp", "/var/tmp", "/tmp", "/temp", 0};
#endif
#if OS_WIN
const char *zTemps[] = { "/temp", "c:/temp", "c:", "d:", "e:", 0};
#endif
const char *zDir;
int i;
struct stat statbuf;
for(i=0; zTemps[i]; i++){
zDir = zTemps[i];
if( stat(zDir, &statbuf)==0 && S_ISDIR(statbuf.st_mode)
&& access(zDir, W_OK|X_OK)==0 ){
break;
}
}
if( zDir==0 ) zDir = ".";
return sqliteDbbeOpenTempFile(zDir, pDbbe, ppFile);
}
/*
** This variable contains pointers to all of the access methods
** used to implement the MEMORY backend.
@ -764,8 +738,6 @@ static struct DbbeMethods memoryMethods = {
/* New */ sqliteMemNew,
/* Put */ sqliteMemPut,
/* Delete */ sqliteMemDelete,
/* OpenTempFile */ sqliteMemOpenTempFile,
/* CloseTempFile */ sqliteDbbeCloseTempFile
};
/*

View File

@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.7 2001/01/15 22:51:10 drh Exp $
** $Id: delete.c,v 1.8 2001/03/20 22:05:00 drh Exp $
*/
#include "sqliteInt.h"
@ -85,48 +85,63 @@ void sqliteDeleteFrom(
v = sqliteGetVdbe(pParse);
if( v==0 ) goto delete_from_cleanup;
/* Begin the database scan
/* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to deleted the database files directly.
*/
sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the key of every item to be deleted.
*/
sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
/* End the database scan loop.
*/
sqliteWhereEnd(pWInfo);
/* Delete every item whose key was written to the list during the
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_OpenIdx, base+i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
if( pTab->pIndex ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j;
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
if( pWhere==0 ){
sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, 0, 0, pIdx->zName, 0);
}
}
sqliteVdbeAddOp(v, OP_Delete, base, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
/* The usual case: There is a WHERE clause so we have to scan through
** the table an pick which records to delete.
*/
else{
/* Begin the database scan
*/
sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the key of every item to be deleted.
*/
sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
/* End the database scan loop.
*/
sqliteWhereEnd(pWInfo);
/* Delete every item whose key was written to the list during the
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_OpenTbl, base, 1, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_OpenIdx, base+i, 1, pIdx->zName, 0);
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
if( pTab->pIndex ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j;
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
}
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
}
}
sqliteVdbeAddOp(v, OP_Delete, base, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
}
delete_from_cleanup:
sqliteIdListDelete(pTabList);

View File

@ -23,7 +23,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.36 2001/01/20 19:52:50 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.37 2001/03/20 22:05:00 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
@ -427,7 +427,4 @@ Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
int sqliteDbbeOpenTempFile(const char*, Dbbe*, FILE**);
void sqliteDbbeCloseTempFile(Dbbe*, FILE*);
void sqliteDbbeCloseAllTempFiles(Dbbe*);
char *sqliteDbbeNameToFile(const char*,const char*,const char*);

View File

@ -41,7 +41,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.52 2001/02/19 23:23:39 drh Exp $
** $Id: vdbe.c,v 1.53 2001/03/20 22:05:00 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
@ -167,6 +167,20 @@ struct SetElem {
char zKey[1]; /* Value of this key */
};
/*
** A Keylist is a bunch of keys into a table. The keylist can
** grow without bound. The keylist stores the keys of database
** records that need to be deleted.
*/
typedef struct Keylist Keylist;
struct Keylist {
int nKey; /* Number of slots in aKey[] */
int nUsed; /* Next unwritten slot in aKey[] */
int nRead; /* Next unread slot in aKey[] */
Keylist *pNext; /* Next block of keys */
int aKey[1]; /* One or more keys. Extra space allocated as needed */
};
/*
** An instance of the virtual machine
*/
@ -188,7 +202,7 @@ struct Vdbe {
int nCursor; /* Number of slots in aCsr[] */
Cursor *aCsr; /* On element of this array for each open cursor */
int nList; /* Number of slots in apList[] */
FILE **apList; /* An open file for each list */
Keylist **apList; /* For each Keylist */
int nSort; /* Number of slots in apSort[] */
Sorter **apSort; /* An open sorter list */
FILE *pFile; /* At most one open file handler */
@ -685,6 +699,17 @@ static int hardNeedStack(Vdbe *p, int N){
return 0;
}
/*
** Delete a keylist
*/
static void KeylistFree(Keylist *p){
while( p ){
Keylist *pNext = p->pNext;
sqliteFree(p);
p = pNext;
}
}
/*
** Clean up the VM after execution.
**
@ -714,10 +739,8 @@ static void Cleanup(Vdbe *p){
p->aMem = 0;
p->nMem = 0;
for(i=0; i<p->nList; i++){
if( p->apList[i] ){
p->pBe->x->CloseTempFile(p->pBe, p->apList[i]);
p->apList[i] = 0;
}
KeylistFree(p->apList[i]);
p->apList[i] = 0;
}
sqliteFree(p->apList);
p->apList = 0;
@ -2431,10 +2454,11 @@ int sqliteVdbeExec(
/* Opcode: ListOpen P1 * *
**
** Open a file used for temporary storage of integer table keys. P1
** will server as a handle to this temporary file for future
** interactions. If another temporary file with the P1 handle is
** already opened, the prior file is closed and a new one opened
** Open a "List" structure used for temporary storage of integer
** table keys. P1
** will server as a handle to this list for future
** interactions. If another list with the P1 handle is
** already opened, the prior list is closed and a new one opened
** in its place.
*/
case OP_ListOpen: {
@ -2442,16 +2466,13 @@ int sqliteVdbeExec(
VERIFY( if( i<0 ) goto bad_instruction; )
if( i>=p->nList ){
int j;
p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(FILE*) );
p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(Keylist*) );
if( p->apList==0 ){ p->nList = 0; goto no_mem; }
for(j=p->nList; j<=i; j++) p->apList[j] = 0;
p->nList = i+1;
}else if( p->apList[i] ){
pBex->CloseTempFile(pBe, p->apList[i]);
}
rc = pBex->OpenTempFile(pBe, &p->apList[i]);
if( rc!=SQLITE_OK ){
sqliteSetString(pzErrMsg, "unable to open a temporary file", 0);
KeylistFree(p->apList[i]);
p->apList[i] = 0;
}
break;
}
@ -2459,19 +2480,26 @@ int sqliteVdbeExec(
/* Opcode: ListWrite P1 * *
**
** Write the integer on the top of the stack
** into the temporary storage file P1.
** into the temporary storage list P1.
*/
case OP_ListWrite: {
int i = pOp->p1;
VERIFY( if( i<0 ) goto bad_instruction; )
Keylist *pKeylist;
VERIFY( if( i<0 || i>=p->nList ) goto bad_instruction; )
VERIFY( if( p->tos<0 ) goto not_enough_stack; )
if( VERIFY( i<p->nList && ) p->apList[i]!=0 ){
int val;
Integerify(p, p->tos);
val = aStack[p->tos].i;
POPSTACK;
fwrite(&val, sizeof(int), 1, p->apList[i]);
pKeylist = p->apList[i];
if( pKeylist==0 || pKeylist->nUsed>=pKeylist->nKey ){
pKeylist = sqliteMalloc( sizeof(Keylist)+999*sizeof(int) );
if( pKeylist==0 ) goto no_mem;
pKeylist->nKey = 1000;
pKeylist->nRead = 0;
pKeylist->nUsed = 0;
pKeylist->pNext = p->apList[i];
p->apList[i] = pKeylist;
}
Integerify(p, p->tos);
pKeylist->aKey[pKeylist->nUsed++] = aStack[p->tos].i;
POPSTACK;
break;
}
@ -2482,9 +2510,7 @@ int sqliteVdbeExec(
case OP_ListRewind: {
int i = pOp->p1;
VERIFY( if( i<0 ) goto bad_instruction; )
if( VERIFY( i<p->nList && ) p->apList[i]!=0 ){
rewind(p->apList[i]);
}
/* This is now a no-op */
break;
}
@ -2497,14 +2523,24 @@ int sqliteVdbeExec(
case OP_ListRead: {
int i = pOp->p1;
int val, amt;
VERIFY(if( i<0 || i>=p->nList || p->apList[i]==0 )goto bad_instruction;)
amt = fread(&val, sizeof(int), 1, p->apList[i]);
if( amt==1 ){
Keylist *pKeylist;
VERIFY(if( i<0 || i>=p->nList ) goto bad_instruction;)
pKeylist = p->apList[i];
if( pKeylist!=0 ){
VERIFY(
if( pKeylist->nRead<0
|| pKeylist->nRead>=pKeylist->nUsed
|| pKeylist->nRead>=pKeylist->nKey ) goto bad_instruction;
)
p->tos++;
if( NeedStack(p, p->tos) ) goto no_mem;
aStack[p->tos].i = val;
aStack[p->tos].i = pKeylist->aKey[pKeylist->nRead++];
aStack[p->tos].flags = STK_Int;
zStack[p->tos] = 0;
if( pKeylist->nRead>=pKeylist->nUsed ){
p->apList[i] = pKeylist->pNext;
sqliteFree(pKeylist);
}
}else{
pc = pOp->p2 - 1;
}
@ -2518,10 +2554,9 @@ int sqliteVdbeExec(
case OP_ListClose: {
int i = pOp->p1;
VERIFY( if( i<0 ) goto bad_instruction; )
if( VERIFY( i<p->nList && ) p->apList[i]!=0 ){
pBex->CloseTempFile(pBe, p->apList[i]);
p->apList[i] = 0;
}
VERIFY( if( i>=p->nList ) goto bad_instruction; )
KeylistFree(p->apList[i]);
p->apList[i] = 0;
break;
}

View File

@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the DELETE FROM statement.
#
# $Id: delete.test,v 1.7 2001/03/20 12:55:14 drh Exp $
# $Id: delete.test,v 1.8 2001/03/20 22:05:00 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -118,4 +118,56 @@ do_test delete-5.7 {
execsql {SELECT f1 FROM table1 ORDER BY f1}
} {48}
# Delete large quantities of data. We want to test the List overflow
# mechanism in the vdbe.
#
do_test delete-6.1 {
set fd [open data1.txt w]
for {set i 1} {$i<=3000} {incr i} {
puts $fd "[expr {$i}]\t[expr {$i*$i}]"
}
close $fd
execsql {DELETE FROM table1}
execsql {COPY table1 FROM 'data1.txt'}
execsql {DELETE FROM table2}
execsql {COPY table2 FROM 'data1.txt'}
file delete data1.txt
execsql {SELECT count(*) FROM table1}
} {3000}
do_test delete-6.2 {
execsql {SELECT count(*) FROM table2}
} {3000}
do_test delete-6.3 {
execsql {SELECT f1 FROM table1 WHERE f1<10 ORDER BY f1}
} {1 2 3 4 5 6 7 8 9}
do_test delete-6.4 {
execsql {SELECT f1 FROM table2 WHERE f1<10 ORDER BY f1}
} {1 2 3 4 5 6 7 8 9}
do_test delete-6.5 {
execsql {DELETE FROM table1 WHERE f1>7}
execsql {SELECT f1 FROM table1 ORDER BY f1}
} {1 2 3 4 5 6 7}
do_test delete-6.6 {
execsql {DELETE FROM table2 WHERE f1>7}
execsql {SELECT f1 FROM table2 ORDER BY f1}
} {1 2 3 4 5 6 7}
do_test delete-6.7 {
execsql {DELETE FROM table1}
execsql {SELECT f1 FROM table1}
} {}
do_test delete-6.8 {
execsql {INSERT INTO table1 VALUES(2,3)}
execsql {SELECT f1 FROM table1}
} {2}
do_test delete-6.9 {
execsql {DELETE FROM table2}
execsql {SELECT f1 FROM table2}
} {}
do_test delete-6.10 {
execsql {INSERT INTO table2 VALUES(2,3)}
execsql {SELECT f1 FROM table2}
} {2}
finish_test

View File

@ -17,6 +17,15 @@ proc chng {date desc} {
puts "<DD><P><UL>$desc</UL></P></DD>"
}
chng {2001 Mar 20 (1.0.27)} {
<li>When doing DELETE and UPDATE, the library used to write the record
numbers of records to be deleted or updated into a temporary file.
This is changed so that the record numbers are held in memory.</li>
<li>The DELETE command without a WHILE clause just removes the database
files from the disk, rather than going through and deleting record
by record.</li>
}
chng {2001 Mar 20 (1.0.26)} {
<li>A serious bug fixed on Windows. Windows users should upgrade.
No impact to Unix.</li>