From 0353cedda4851e4d653b70421ed7445f62a2688a Mon Sep 17 00:00:00 2001
From: drh
Date: Tue, 20 Mar 2001 22:05:00 +0000
Subject: [PATCH] Enhancements to the DELETE command (CVS 194)
FossilOrigin-Name: daea156e2430762e683ff5460f9f8bb3204ae168
---
VERSION | 2 +-
manifest | 30 +++++++-------
manifest.uuid | 2 +-
src/dbbe.c | 88 +--------------------------------------
src/dbbe.h | 13 ++----
src/dbbegdbm.c | 14 +------
src/dbbemem.c | 30 +-------------
src/delete.c | 95 ++++++++++++++++++++++++------------------
src/sqliteInt.h | 5 +--
src/vdbe.c | 105 +++++++++++++++++++++++++++++++----------------
test/delete.test | 54 +++++++++++++++++++++++-
www/changes.tcl | 9 ++++
12 files changed, 211 insertions(+), 236 deletions(-)
diff --git a/VERSION b/VERSION
index 8955a0173e..adb7b04cb2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.26
+1.0.27
diff --git a/manifest b/manifest
index e092172dc8..c4e9b7cd81 100644
--- a/manifest
+++ b/manifest
@@ -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
diff --git a/manifest.uuid b/manifest.uuid
index 97f6034d99..167435563a 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-99f9ea412f87cfb518cfb34f0e187fd1baf56761
\ No newline at end of file
+daea156e2430762e683ff5460f9f8bb3204ae168
\ No newline at end of file
diff --git a/src/dbbe.c b/src/dbbe.c
index da99eb9e5a..f637f5388c 100644
--- a/src/dbbe.c
+++ b/src/dbbe.c
@@ -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
@@ -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; inTemp; 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; inTemp; 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; inTemp; 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
diff --git a/src/dbbe.h b/src/dbbe.h
index 09166469d5..6a386adf9a 100644
--- a/src/dbbe.h
+++ b/src/dbbe.h
@@ -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_) */
diff --git a/src/dbbegdbm.c b/src/dbbegdbm.c
index eb4d482e7f..777c7dacef 100644
--- a/src/dbbegdbm.c
+++ b/src/dbbegdbm.c
@@ -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
@@ -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
};
diff --git a/src/dbbemem.c b/src/dbbemem.c
index 7d03a5faef..6bf1cc0f2f 100644
--- a/src/dbbemem.c
+++ b/src/dbbemem.c
@@ -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
@@ -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
};
/*
diff --git a/src/delete.c b/src/delete.c
index d5e5a3b01e..c4da286220 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -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; jnColumn; 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; jnColumn; 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);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 22f49b405c..371eafabdd 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -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*);
diff --git a/src/vdbe.c b/src/vdbe.c
index 324730f701..1e852f3975 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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
@@ -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; inList; 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( inList && ) 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( inList && ) 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( inList && ) 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;
}
diff --git a/test/delete.test b/test/delete.test
index d8c6f56185..4587fbf9f7 100644
--- a/test/delete.test
+++ b/test/delete.test
@@ -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
diff --git a/www/changes.tcl b/www/changes.tcl
index c12e98e825..111276c81a 100644
--- a/www/changes.tcl
+++ b/www/changes.tcl
@@ -17,6 +17,15 @@ proc chng {date desc} {
puts "
"
}
+chng {2001 Mar 20 (1.0.27)} {
+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.
+The DELETE command without a WHILE clause just removes the database
+ files from the disk, rather than going through and deleting record
+ by record.
+}
+
chng {2001 Mar 20 (1.0.26)} {
A serious bug fixed on Windows. Windows users should upgrade.
No impact to Unix.