1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Perform deletes in a single pass. (CVS 2104)

FossilOrigin-Name: a2e1c35b327e33684ab19e5f65727c42c7b2949c
This commit is contained in:
danielk1977
2004-11-16 15:50:19 +00:00
parent 6a43f9b3ff
commit ed326d7047
14 changed files with 205 additions and 229 deletions

View File

@@ -1,5 +1,5 @@
C Allow\sbtree\scursors\sto\spersist\sthrough\sBtreeDelete()\scalls.\s(CVS\s2103)
D 2004-11-16T04:57:24
C Perform\sdeletes\sin\sa\ssingle\spass.\s(CVS\s2104)
D 2004-11-16T15:50:20
F Makefile.in e747bb5ba34ccbdd81f79dcf1b2b33c02817c21d
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
@@ -29,11 +29,11 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
F src/btree.c 967b42616d0dc06d1bc9eb12d0af95252163df01
F src/btree.c c878e87a415a429a335bf26d834a311c5c40f5d1
F src/btree.h 861e40b759a195ba63819740e484390012cf81ab
F src/build.c a95eb1181247368b0ffe2eed121a43735976a964
F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f
F src/delete.c f0af21a1ede15524a5edd59fe10ef486283a1ee9
F src/delete.c be9d039b819f4a5d0fdfaeceace139ba189ef819
F src/expr.c 4ee3e47358c92a919062255b14057a7a8f641e01
F src/func.c 181ea4b8bbc621457838494a440d2e4e2307ab70
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
@@ -58,10 +58,10 @@ F src/parse.y 3282026b619e1c7f932fd8ecef9627fa86da048a
F src/pragma.c 0b43b8cac4870bfa041bf2ca29d7ce47b76362d6
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 156990c636102bb6b8de85e7ff3396a62568476b
F src/select.c cf4b7952d6d214931c52636ee726f19ee2a275c5
F src/shell.c 55adda3cf3c1cc2f6c1919aac17b2318f9c2a96f
F src/sqlite.h.in a44eac0716bf4751447160d5c8ed049ece66d45a
F src/sqliteInt.h 8569ce94e891a854de71d7bd628da1d25ee6dfe4
F src/sqliteInt.h dd26056a172a5d488a78846b5ed8db6953db4e5d
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c 7f1a1a678140e6901c8954590ca2aabe50b48f71
F src/test1.c 8c330b53aa04d234ea7da6a90141ce9958a8901c
@@ -71,7 +71,7 @@ F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
F src/tokenize.c 2ad3d1ae1a0a70746db0b31a0a74f58050a3c39a
F src/trigger.c 0c91b56182560263733e4b035acdb939bd1cf0e2
F src/update.c 3cc67f6053495152e82a6a48c93ed331218e936e
F src/update.c 395a2b270dfcbc96c20e40c9cb42b0533768ce30
F src/utf.c e45ce11be6922408cd381561721f6cca7d3b992a
F src/util.c 005fdf2d008f3429d081766ad6098fdd86d8d8e6
F src/vacuum.c ecb4a2c6f1ac5cc9b394dc64d3bb14ca650c4f60
@@ -81,7 +81,7 @@ F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b
F src/vdbeapi.c 74be7f96c0a1ac275661f8b32276ac521d9ce37c
F src/vdbeaux.c c6da55e0096e141211f918837eca98e0be6400b4
F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0
F src/where.c 6e637a6b3e61fe3104adc4e5caa4738bf6570daa
F src/where.c 4d28167e450255372b45abf1bc8cd5f0e9264d7b
F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c
F test/alter.test ea6b104fa83da6970b1ce61885827817bdaced3a
F test/attach.test e305dd59a375e37c658c6d401f19f8a95880bf9a
@@ -101,9 +101,9 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f
F test/btree8.test f0841e71ea311faf3fa04d5c80a75ccb9dc6d2c9
F test/capi2.test 1ec97bf8896185aec2366c7d07b01edef6ae4b7e
F test/capi3.test c9b162838cda7f61c6cfefed304b69287f2fc688
F test/btree8.test 12db22f6963d9b33a5aa8e8b766033afc82b22c2
F test/capi2.test cd5e149564094bda9a587e70ec5949863222cd23
F test/capi3.test da88858ea5318c0cbd0990be9d8db0237496a3dc
F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336
F test/collate1.test f79736d2ebf5492167ee4d1f4ab4c09dda776b03
F test/collate2.test 12fd658d8f5106a8a5c8a77d66919d8c89394036
@@ -117,7 +117,7 @@ F test/crash.test 48b481769dd0ead25b0dfc0150853bfa39a3b65c
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/date.test dda578ec1857837156bd8b32f8e09d81d7d7881c
F test/delete.test fc29491f6a7ac899ce29f4549a104809e245d9a6
F test/delete2.test 1d3f99f52f50eb6ed10c803f80540a6857307a7d
F test/delete2.test 04a19e248d88156324ae964676bb4584b65b46f4
F test/diskfull.test e2f6cfd868713ead06dc82b84a4938e868128fc0
F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52
F test/enc2.test 6d1a2650e9da43eab499d18ca694a0cb6ec69dee
@@ -140,7 +140,7 @@ F test/join4.test 8dec387d06b3a4685e1104048065cf5236b99b93
F test/lastinsert.test 09ac3a359ced3d4510feccc0dcbae3d80e449cf9
F test/laststmtchanges.test 9cb56c5935103cacd0070d9d25d8dde322928db1
F test/limit.test f7c06fccd76755e8d083b61c06bc31cf461b9c35
F test/lock.test 7cb9395919a0986ee4dd08bd49d34df93c8fc4fe
F test/lock.test ba72c211499b0874c56643b9ede1df4018bb20de
F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f
F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
F test/main.test 5f9deae11b93336da1ccc5f91cf8be075c91ddf1
@@ -149,7 +149,7 @@ F test/memdb.test 34ee8598de307a16ccc3ac91b85cee9c668ae5ed
F test/memleak.test f1fa233f8295dd1d955a00d5e5ee857850f27f29
F test/minmax.test c0f92d3f7b11656221735385f2c8b1878bbbdaf6
F test/misc1.test 744f60d1025fa978708b96cb222a07a1feb1524a
F test/misc2.test 9d9403f7e6092699f3f92bb1e26ff55165528e7c
F test/misc2.test 53cf5e931547962563df3600f85ba49e86ffa1fe
F test/misc3.test 928a2f1e1189924ed14e1ae074e34f40688bdf94
F test/misc4.test d005a75f095bb04db09a5d096144405ae566b622
F test/misuse.test 2d7c46160f7c214f761fc5d030684a37ae8832a6
@@ -258,7 +258,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
P 33c9b647aa70d1a9dab0e999daf853aa71d7df37
R 50b298d755ddcbf483d54572fec74d25
P 6ad5fc8e1a119b750a82fc1426704164a2042d57
R db6ab1c6b37169af000d8cc9fa56bcb7
U danielk1977
Z 8f5fe953592a6b674b59302a9768154c
Z 9bd342e5e06ad9732b13806797d3998c

View File

@@ -1 +1 @@
6ad5fc8e1a119b750a82fc1426704164a2042d57
a2e1c35b327e33684ab19e5f65727c42c7b2949c

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.218 2004/11/16 04:57:24 danielk1977 Exp $
** $Id: btree.c,v 1.219 2004/11/16 15:50:20 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -4307,11 +4307,6 @@ static int balance(MemPage *pPage){
** then this routine returns SQLITE_OK.
*/
static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){
BtCursor *p;
for(p=pBt->pCursor; p; p=p->pNext){
if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
if( p->wrFlag==0 ) return SQLITE_LOCKED;
}
return SQLITE_OK;
}
@@ -4512,7 +4507,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){
BtCursor leafCur;
unsigned char *pNext;
int szNext;
int notUsed;
unsigned char *tempCell;
assert( !pPage->leafData );

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.88 2004/11/05 17:17:50 drh Exp $
** $Id: delete.c,v 1.89 2004/11/16 15:50:20 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -64,7 +64,6 @@ void sqlite3OpenTableForReading(
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
}
/*
** Process a DELETE FROM statement.
*/
@@ -76,7 +75,7 @@ void sqlite3DeleteFrom(
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
const char *zDb; /* Name of database holding pTab */
int end, addr = 0; /* A couple addresses of generated code */
int addr = 0; /* A couple addresses of generated code */
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
@@ -150,10 +149,15 @@ void sqlite3DeleteFrom(
oldIdx = pParse->nTab++;
}
/* Resolve the column names in all the expressions.
/* Resolve the column names in all the expressions. Allocate cursors
** for the table and indices first, in case an expression needs to use
** a cursor (e.g. an IN() expression).
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
pParse->nTab++;
}
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
goto delete_from_cleanup;
}
@@ -227,22 +231,6 @@ void sqlite3DeleteFrom(
}
}
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the key of every item to be deleted.
*/
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( row_triggers_exist ){
@@ -250,81 +238,50 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
}
/* 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.
*/
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
end = sqlite3VdbeMakeLabel(v);
/* Open cursors for the table and indices we are deleting from. */
if( !isView ){
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
}
/* This is the beginning of the delete loop when there are
** row triggers.
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, isView?0:iCur);
if( pWInfo==0 ) goto delete_from_cleanup;
addr = pWInfo->iContinue;
/* If row-triggers exist, copy the record being deleted into the
** oldIdx psuedo-table. Then invoke the BEFORE triggers.
*/
if( row_triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
if( !isView ){
sqlite3OpenTableForReading(v, iCur, pTab);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
if( !isView ){
/* Open cursors for the table we are deleting from and all its
** indices. If there are row triggers, this happens inside the
** OP_ListRead loop because the cursor have to all be closed
** before the trigger fires. If there are no row triggers, the
** cursors are opened only once on the outside the loop.
/* Delete the row. Increment the callback value if the count-rows flag
** is set.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !row_triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
/* Delete the row */
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
}
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
/* Code the AFTER triggers. */
if( row_triggers_exist ){
if( !isView ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
/* End of the delete loop */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close the cursors after the loop if there are no row triggers */
if( !row_triggers_exist ){
/* End the database scan loop and close indices. */
sqlite3WhereEnd(pWInfo);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
}
/*

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.213 2004/10/31 02:22:49 drh Exp $
** $Id: select.c,v 1.214 2004/11/16 15:50:20 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -2523,7 +2523,7 @@ int sqlite3Select(
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
pGroupBy ? 0 : &pOrderBy);
pGroupBy ? 0 : &pOrderBy, -1);
if( pWInfo==0 ) goto select_end;
/* Use the standard inner loop if we are not dealing with

View File

@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.339 2004/11/12 13:42:31 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.340 2004/11/16 15:50:20 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1313,9 +1313,10 @@ void sqlite3SelectUnbind(Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int);
void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**, int);
void sqlite3WhereEnd(WhereInfo*);
void sqlite3ExprCode(Parse*, Expr*);
int sqlite3ExprCodeExprList(Parse*, ExprList*);

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.94 2004/11/05 17:17:50 drh Exp $
** $Id: update.c,v 1.95 2004/11/16 15:50:20 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -235,7 +235,7 @@ void sqlite3Update(
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, -1);
if( pWInfo==0 ) goto update_cleanup;
/* Remember the index of every item to be updated.

View File

@@ -12,7 +12,7 @@
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.
**
** $Id: where.c,v 1.116 2004/10/04 13:38:09 drh Exp $
** $Id: where.c,v 1.117 2004/11/16 15:50:20 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -471,13 +471,18 @@ static void codeEqualityTerm(
**
** If the where clause loops cannot be arranged to provide the correct
** output order, then the *ppOrderBy is unchanged.
**
** If parameter iTabCur is non-negative, then it is a cursor already open
** on table pTabList->aSrc[0]. Use this cursor instead of opening a new
** one.
*/
WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
int pushKey, /* If TRUE, leave the table key on the stack */
ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
int iTabCur /* Cursor for pTabList->aSrc[0] */
){
int i; /* Loop counter */
WhereInfo *pWInfo; /* Will become the return value of this function */
@@ -773,7 +778,9 @@ WhereInfo *sqlite3WhereBegin(
pTab = pTabList->a[i].pTab;
if( pTab->isTransient || pTab->pSelect ) continue;
if( i>0 || iTabCur<0 ){
sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab);
}
sqlite3CodeVerifySchema(pParse, pTab->iDb);
if( (pIx = pWInfo->a[i].pIdx)!=0 ){
sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);

View File

@@ -13,15 +13,65 @@
# this file tests that existing cursors are correctly repositioned
# when entries are inserted into or deleted from btrees.
#
# $Id: btree8.test,v 1.2 2004/11/16 04:57:25 danielk1977 Exp $
# $Id: btree8.test,v 1.3 2004/11/16 15:50:21 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Test organization:
#
# btree-8.1.*: Test cursor persistence when inserting records into tables.
# btree-8.2.*: Test cursor persistence when deleting records from tables.
# btree-8.3.*: Test cursor persistence when inserting records into indices.
# btree-8.4.*: Test cursor persistence when deleting records from indices.
#
# Transform the number $num into a string of length $len by repeating the
# string representation of the number as many times as necessary. Repeats
# are seperated by a '.' character. Eg:
#
# [num_to_string 456 10] -> "456.456.45"
#
proc num_to_string {num len} {
set num [format %.4d $num]
return [string range [string repeat "$num." $len] 0 [expr $len-1]]
}
# Proc lshuffle takes a list as an argument and returns a copy of that
# list in randomized order. It uses the K-combinator for speed.
#
proc K {x y} {set x}
proc lshuffle { list } {
set n [llength $list]
while {$n>0} {
set j [expr {int(rand()*$n)}]
lappend slist [lindex $list $j]
set list [lreplace [K $list [set list {}]] $j $j]
incr n -1
}
return $slist
}
# Proc lremove takes two arguments, a list (the first argument) and a key
# (the second argument). A copy of the list is returned with all elements
# equal to $key removed.
#
proc lremove {list key} {
while { [set i [lsearch $list $key]] != -1 } {
set list [concat \
[lrange $list 0 [expr $i-1]] \
[lrange $list [expr $i+1] end]
]
}
return $list
}
# Use the SQL interface to create a couple of btree tables, one using
# the flags for an SQL table, the other an SQL index.
#
do_test btree8-1.0 {
do_test btree8-0.0 {
execsql {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
CREATE INDEX i1 ON t1(b);
@@ -31,6 +81,16 @@ set tnum [execsql {SELECT rootpage FROM sqlite_master where type = 'table'}]
set inum [execsql {SELECT rootpage FROM sqlite_master where type = 'index'}]
db close
#-------------------------------------------------------------------------
# Tests btree8-1.* insert a handful of records (~10) into the type of
# b-tree created for an SQL table. The records have integer keys in the
# range 1..5000. A cursor is left pointing to each of these records.
# Then, a record is inserted for each key value between 1 and 5000,
# including the values for which a record already exists (overwriting
# the original). After each record is inserted, the existing cursors
# are checked to ensure they still point at the same key-value.
#
# Open the database at the btree level and begin a transaction
do_test btree8-1.1 {
set ::bt [btree_open test.db 100 0]
@@ -79,6 +139,14 @@ for {set i $testnum} {$i < 5000 && $nErr==0 } {incr i} {
}
}
#-------------------------------------------------------------------------
# Tests btree8-2.* loop through the tree created by tests btree8-1.*,
# deleting records in sequential order. After each record is deleted,
# each of the open cursors is checked to ensure that it still points
# to the same key-value or, if that key value has been deleted, returns
# 0 as the integer key value.
#
# Now delete entries from the table.
btree_first $::write_csr
for {set i $first_entry} {$i < 5000 && $nErr==0 } {incr i} {
@@ -103,6 +171,7 @@ for {set i $first_entry} {$i < 5000 && $nErr==0 } {incr i} {
}
}
# Close all existing cursors and conclude the open transaction.
btree_close_cursor $::write_csr
btree_commit $::bt
if {$::nErr>0} { puts $::csr_list ; exit }
@@ -111,16 +180,12 @@ foreach csr $csr_list {
}
set csr_list [list]
# Transform the number $num into a string of length $len by repeating the
# string representation of the number as many times as necessary. Repeats
# are seperated by a '.' character. Eg:
#-------------------------------------------------------------------------
# Tests btree8-3.* are analogous to btree8-1.*, but use the type of btree
# created for an SQL index, not an SQL table. Instead of integers, key
# values are strings 20 bytes long created by transforming integers
# into string using the [num_to_string] proc (see above).
#
# [num_to_string 456 10] -> "456.456.45"
#
proc num_to_string {num len} {
set num [format %.4d $num]
return [string range [string repeat "$num." $len] 0 [expr $len-1]]
}
foreach key $keys {
lappend skeys [num_to_string $key 20]
@@ -144,8 +209,6 @@ foreach key $skeys {
}
btree_commit $::bt
# set btree_trace 1
# Now write more entries to the index (and overwrite the ones that exist).
# After each write, check that the cursors created above still point to the
# same entries.
@@ -170,21 +233,13 @@ for {set i $testnum} {$i < 5000 && $nErr==0 } {incr i} {
btree_commit $::bt
btree_begin_transaction $::bt
proc lremove {l key} {
set idx [lsearch $l $key]
return [concat [lrange $l 0 [expr $idx-1]] [lrange $l [expr $idx+1] end]]
}
proc K {x y} {set x}
proc lshuffle { list } {
set n [llength $list]
while {$n>0} {
set j [expr {int(rand()*$n)}]
lappend slist [lindex $list $j]
set list [lreplace [K $list [set list {}]] $j $j]
incr n -1
}
return $slist
}
#-------------------------------------------------------------------------
# Tests btree8-4.* are analogous to btree8-2.*, but use the type of btree
# created for an SQL index, not an SQL table. Instead of integers, key
# values are strings 20 bytes long created by transforming integers
# into string using the [num_to_string] proc (see above). Also, keys
# are deleted in random order, calculated by the [lshuffle] proc (see above).
#
# Now delete entries from the index. Do this in a random order, to try to
# ensure that internal and external nodes are deleted.
@@ -202,7 +257,6 @@ foreach i $delete_order {
do_test btree8-4.$i.2 {
btree_delete $::write_csr
} {}
set delete_order [lremove $delete_order $i]
set testnum 2
foreach csr $csr_list key $keys {

View File

@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi2.test,v 1.20 2004/11/03 16:27:02 drh Exp $
# $Id: capi2.test,v 1.21 2004/11/16 15:50:21 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -450,15 +450,22 @@ do_test capi2-6.12 {
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 5 {x counter}}
# The next test used to report that the database was locked.
# As of 3.1 this is no longer the case, the UPDATE works
# even though there is a SELECT active on the table. Rows
# scanned by subsequent calls to sqlite3_step report the
# updated values.
#
do_test capi2-6.13 {
catchsql {UPDATE t3 SET x=x+1}
} {1 {database table is locked}}
} {0 {}}
do_test capi2-6.14 {
list [sqlite3_step $VM1] \
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 6 {x counter}}
} {SQLITE_ROW 1 7 {x counter}}
do_test capi2-6.15 {
execsql {SELECT * FROM t1}
} {1 2 3}
@@ -467,7 +474,7 @@ do_test capi2-6.16 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 7 {x counter}}
} {SQLITE_ROW 1 8 {x counter}}
do_test capi2-6.17 {
catchsql {UPDATE t1 SET b=b+1}
} {0 {}}
@@ -476,7 +483,7 @@ do_test capi2-6.18 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 8 {x counter}}
} {SQLITE_ROW 1 9 {x counter}}
do_test capi2-6.19 {
execsql {SELECT * FROM t1}
} {1 3 3}
@@ -485,7 +492,7 @@ do_test capi2-6.20 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 9 {x counter}}
} {SQLITE_ROW 1 10 {x counter}}
#do_test capi2-6.21 {
# execsql {ROLLBACK; SELECT * FROM t1}
#} {1 2 3}
@@ -494,7 +501,7 @@ do_test capi2-6.22 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 10 {x counter}}
} {SQLITE_ROW 1 11 {x counter}}
#do_test capi2-6.23 {
# execsql {BEGIN TRANSACTION;}
#} {}
@@ -503,7 +510,7 @@ do_test capi2-6.24 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 11 {x counter}}
} {SQLITE_ROW 1 12 {x counter}}
do_test capi2-6.25 {
execsql {
INSERT INTO t1 VALUES(2,3,4);
@@ -515,7 +522,7 @@ do_test capi2-6.26 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 12 {x counter}}
} {SQLITE_ROW 1 13 {x counter}}
do_test capi2-6.27 {
catchsql {
INSERT INTO t1 VALUES(2,4,5);
@@ -527,7 +534,7 @@ do_test capi2-6.28 {
[sqlite3_column_count $VM1] \
[get_row_values $VM1] \
[get_column_names $VM1]
} {SQLITE_ROW 1 13 {x counter}}
} {SQLITE_ROW 1 14 {x counter}}
do_test capi2-6.99 {
sqlite3_finalize $VM1
} {SQLITE_OK}

View File

@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3.test,v 1.23 2004/11/14 21:56:31 drh Exp $
# $Id: capi3.test,v 1.24 2004/11/16 15:50:21 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -759,11 +759,16 @@ do_test capi3-12.2 {
INSERT INTO t1 VALUES(3, NULL);
}
} {0 {}}
# The following test used to report "database is locked". As of 3.10
# this is no longer the case, the INSERT is legal. The inserted row
# will be returned after all others (because the scan is being done
# in rowid order).
do_test capi3-12.3 {
catchsql {
INSERT INTO t2 VALUES(4);
}
} {1 {database table is locked}}
} {0 {}}
do_test capi3-12.4 {
catchsql {
BEGIN;
@@ -775,16 +780,18 @@ do_test capi3-12.5 {
} {SQLITE_ROW}
do_test capi3-12.6 {
sqlite3_step $STMT
} {SQLITE_DONE}
} {SQLITE_ROW}
do_test capi3-12.7 {
sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3-12.8 {
sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3-12.8 {
do_test capi3-12.9 {
execsql {
COMMIT;
SELECT a FROM t1;
}
} {1 2 3 4}
finish_test

View File

@@ -29,7 +29,7 @@
# The solution to the problem was to detect that the table is locked
# before the index entry is deleted.
#
# $Id: delete2.test,v 1.2 2004/11/04 14:47:13 drh Exp $
# $Id: delete2.test,v 1.3 2004/11/16 15:50:21 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -66,27 +66,26 @@ do_test delete2-1.4 {
} SQLITE_ROW
integrity_check delete2-1.5
# Try to delete a row from the table. The delete should fail.
# Try to delete a row from the table. Before version 3.10 the DELETE
# would fail because of the SELECT active on the table. In 3.10 the
# DELETE is legal.
#
do_test delete2-1.6 {
catchsql {
DELETE FROM q WHERE rowid=1
}
} {1 {database table is locked}}
} {0 {}}
integrity_check delete2-1.7
do_test delete2-1.8 {
execsql {
SELECT * FROM q;
}
} {hello id.1 goodbye id.2 again id.3}
} {goodbye id.2 again id.3}
# Finalize the query, thus clearing the lock on the table. Then
# retry the delete. The delete should work this time.
#
do_test delete2-1.9 {
sqlite3_finalize $STMT
catchsql {
DELETE FROM q WHERE rowid=1
DELETE FROM q WHERE rowid=2
}
} {0 {}}
integrity_check delete2-1.10
@@ -94,6 +93,6 @@ do_test delete2-1.11 {
execsql {
SELECT * FROM q;
}
} {goodbye id.2 again id.3}
} {again id.3}
finish_test

View File

@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script is database locks.
#
# $Id: lock.test,v 1.27 2004/08/07 23:54:48 drh Exp $
# $Id: lock.test,v 1.28 2004/11/16 15:50:21 danielk1977 Exp $
set testdir [file dirname $argv0]
@@ -98,16 +98,17 @@ do_test lock-1.17 {
set x
} {8 9}
# You cannot UPDATE a table from within the callback of a SELECT
# on that same table because the SELECT has the table locked.
# Previously, this test ensured that you cannot UPDATE a table from within the
# callback of a SELECT on that same table because the SELECT has the table
# locked. But as of 3.10 you can do this, so the test is removed.
#
do_test lock-1.18 {
db eval {SELECT * FROM t1} qv {
set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
lappend r $msg
}
set r
} {1 {database table is locked}}
#do_test lock-1.18 {
# db eval {SELECT * FROM t1} qv {
# set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
# lappend r $msg
# }
# set r
#} {1 {database table is locked}}
# But you can UPDATE a different table from the one that is used in
# the SELECT.

View File

@@ -13,7 +13,7 @@
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc2.test,v 1.13 2004/11/04 04:42:28 drh Exp $
# $Id: misc2.test,v 1.14 2004/11/16 15:50:21 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -131,57 +131,6 @@ do_test misc2-6.1 {
}
} {1 2}
# Make sure we get an error message (not a segfault) on an attempt to
# update a table from within the callback of a select on that same
# table.
#
do_test misc2-7.1 {
db close
file delete -force test.db
sqlite3 db test.db
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
}
set rc [catch {
db eval {SELECT rowid FROM t1} {} {
db eval "DELETE FROM t1 WHERE rowid=$rowid"
}
} msg]
lappend rc $msg
} {1 {database table is locked}}
do_test misc2-7.2 {
set rc [catch {
db eval {SELECT rowid FROM t1} {} {
db eval "INSERT INTO t1 VALUES(3)"
}
} msg]
lappend rc $msg
} {1 {database table is locked}}
do_test misc2-7.3 {
db close
file delete -force test.db
sqlite3 db :memory:
execsql {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
}
set rc [catch {
db eval {SELECT rowid FROM t1} {} {
db eval "DELETE FROM t1 WHERE rowid=$rowid"
}
} msg]
lappend rc $msg
} {1 {database table is locked}}
do_test misc2-7.4 {
set rc [catch {
db eval {SELECT rowid FROM t1} {} {
db eval "INSERT INTO t1 VALUES(3)"
}
} msg]
lappend rc $msg
} {1 {database table is locked}}
# Ticket #453. If the SQL ended with "-", the tokenizer was calling that
# an incomplete token, which caused problem. The solution was to just call
# it a minus sign.