Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make sqlite3_count_changes() and total_changes() work with "DELETE FROM |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
e68e4282adb9003aa297d033aeb5d9ca |
User & Date: | danielk1977 2008-10-27 13:59:34.000 |
Context
2008-10-27
| ||
15:34 | If an SQLITE_DELETE authorization callback returns SQLITE_IGNORE, proceed with the delete operation but disable the truncate optimization. (CVS 5845) (check-in: 65a2e13173 user: danielk1977 tags: trunk) | |
13:59 |
Make sqlite3_count_changes() and total_changes() work with "DELETE FROM | |
08:24 | Remove some if() conditions that are always true from delete.c. (CVS 5843) (check-in: 297ad90dd3 user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.526 2008/10/27 13:59:34 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
6183 6184 6185 6186 6187 6188 6189 | ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ MemPage *pParent, /* Parent page. NULL for the root */ | | > | | > > > > > > > | | | 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 | ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ MemPage *pParent, /* Parent page. NULL for the root */ int freePageFlag, /* Deallocate page if true */ int *pnChange ){ MemPage *pPage = 0; int rc; unsigned char *pCell; int i; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>pagerPagecount(pBt->pPager) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage); if( rc ) goto cleardatabasepage_out; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), pPage, 1, pnChange); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage, 1, pnChange); if( rc ) goto cleardatabasepage_out; }else if( pnChange ){ assert( pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ rc = freePage(pPage); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[0] | PTF_LEAF); } cleardatabasepage_out: releasePage(pPage); return rc; } /* ** Delete all information from a single table in the database. iTable is ** the page number of the root of the table. After this routine returns, ** the root page is empty, but still exists. ** ** This routine will fail with SQLITE_LOCKED if there are any open ** read cursors on the table. Open write cursors are moved to the ** root of the table. ** ** If pnChange is not NULL, then table iTable must be an intkey table. The ** integer value pointed to by pnChange is incremented by the number of ** entries in the table. */ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); pBt->db = p->db; if( p->inTrans!=TRANS_WRITE ){ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; }else if( (rc = checkReadLocks(p, iTable, 0, 1))!=SQLITE_OK ){ /* nothing to do */ }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){ /* nothing to do */ }else{ rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0, pnChange); } sqlite3BtreeLeave(p); return rc; } /* ** Erase all information in a table and add the root of the table to |
︙ | ︙ | |||
6290 6291 6292 6293 6294 6295 6296 | */ if( pBt->pCursor ){ return SQLITE_LOCKED; } rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; | | | 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 | */ if( pBt->pCursor ){ return SQLITE_LOCKED; } rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ){ releasePage(pPage); return rc; } *piMoved = 0; |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** ** @(#) $Id: btree.h,v 1.105 2008/10/27 13:59:34 danielk1977 Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ |
︙ | ︙ | |||
113 114 115 116 117 118 119 | ** of the following flags: */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_ZERODATA 2 /* Table has keys only - no data */ #define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */ int sqlite3BtreeDropTable(Btree*, int, int*); | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | ** of the following flags: */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_ZERODATA 2 /* Table has keys only - no data */ #define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */ int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); void sqlite3BtreeTripAllCursors(Btree*, int); int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ int iTable, /* Index of root page */ |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** ** $Id: delete.c,v 1.184 2008/10/27 13:59:34 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
229 230 231 232 233 234 235 | Index *pIdx; /* For looping over indices of the table */ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ NameContext sNC; /* Name context to resolve expressions in */ int iDb; /* Database number */ | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | Index *pIdx; /* For looping over indices of the table */ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ NameContext sNC; /* Name context to resolve expressions in */ int iDb; /* Database number */ int memCnt = -1; /* Memory cell used for change counting */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ int triggers_exist = 0; /* True if any triggers exist */ #endif int iBeginAfterTrigger; /* Address of after trigger program */ int iEndAfterTrigger; /* Exit of after trigger program */ |
︙ | ︙ | |||
368 369 370 371 372 373 374 | #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Note, however, that ** this means that the row change count will be incorrect. */ if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){ assert( !isView ); | < < < < < < < < < < | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Note, however, that ** this means that the row change count will be incorrect. */ if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){ assert( !isView ); sqlite3VdbeAddOp3(v, OP_Clear, pTab->tnum, iDb, memCnt); if( !pParse->nested ){ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); } |
︙ | ︙ |
Changes to src/test3.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test3.c,v 1.102 2008/10/27 13:59:34 danielk1977 Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
385 386 387 388 389 390 391 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; sqlite3BtreeEnter(pBt); | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; sqlite3BtreeEnter(pBt); rc = sqlite3BtreeClearTable(pBt, iTable, 0); sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return TCL_OK; } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.783 2008/10/27 13:59:34 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
4038 4039 4040 4041 4042 4043 4044 | sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1); } #endif } break; } | | > > > > > > > | > > > > > > > > | 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 | sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1); } #endif } break; } /* Opcode: Clear P1 P2 P3 ** ** Delete all contents of the database table or index whose root page ** in the database file is given by P1. But, unlike Destroy, do not ** remove the table or index from the database file. ** ** The table being clear is in the main database file if P2==0. If ** P2==1 then the table to be clear is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** ** If the P3 value is non-zero, then the table refered to must be an ** intkey table (an SQL table, not an index). In this case the row change ** count is incremented by the number of rows in the table being cleared. ** If P3 is greater than zero, then the value stored in register P3 is ** also incremented by the number of rows in the table being cleared. ** ** See also: Destroy */ case OP_Clear: { int nChange = 0; assert( (p->btreeMask & (1<<pOp->p2))!=0 ); rc = sqlite3BtreeClearTable( db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) ); if( pOp->p3 ){ p->nChange += nChange; if( pOp->p3>0 ){ p->aMem[pOp->p3].u.i += nChange; } } break; } /* Opcode: CreateTable P1 P2 * * * ** ** Allocate a new table in the main database file if P1==0 or in the ** auxiliary database file if P1==1 or in an attached database if |
︙ | ︙ |
Changes to test/laststmtchanges.test.
1 2 3 4 5 6 7 | # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # | > | 1 2 3 4 5 6 7 8 | # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # |
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # statement). # Note 2: changes() is changed within the context of a trigger much like # last_insert_rowid() (see lastinsert.test), but is restored once # the trigger exits. # Note 3: changes() is not changed by a change to a view (since everything # is done within instead of trigger context). # set testdir [file dirname $argv0] source $testdir/tester.tcl # ---------------------------------------------------------------------------- # 1.x - basic tests (no triggers) | > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # statement). # Note 2: changes() is changed within the context of a trigger much like # last_insert_rowid() (see lastinsert.test), but is restored once # the trigger exits. # Note 3: changes() is not changed by a change to a view (since everything # is done within instead of trigger context). # # $Id: laststmtchanges.test,v 1.7 2008/10/27 13:59:34 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # ---------------------------------------------------------------------------- # 1.x - basic tests (no triggers) |
︙ | ︙ | |||
274 275 276 277 278 279 280 281 | catchsql { select n from n2; } } {0 {0 1 0 3}} } ;# ifcapable view finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | catchsql { select n from n2; } } {0 {0 1 0 3}} } ;# ifcapable view # ---------------------------------------------------------------------------- # 6.x - Test "DELETE FROM <table>" in the absence of triggers # do_test laststmtchanges-6.1 { execsql { CREATE TABLE t3(a, b, c); INSERT INTO t3 VALUES(1, 2, 3); INSERT INTO t3 VALUES(4, 5, 6); } } {} do_test laststmtchanges-6.2 { execsql { BEGIN; DELETE FROM t3; SELECT changes(); } } {2} do_test laststmtchanges-6.3 { execsql { ROLLBACK; BEGIN; DELETE FROM t3 WHERE a IS NOT NULL; SELECT changes(); } } {2} do_test laststmtchanges-6.4 { execsql { ROLLBACK; CREATE INDEX t3_i1 ON t3(a); BEGIN; DELETE FROM t3; SELECT changes(); } } {2} do_test laststmtchanges-6.5 { execsql { ROLLBACK } set nTotalChange [execsql {SELECT total_changes()}] expr 0 } {0} do_test laststmtchanges-6.6 { execsql { SELECT total_changes(); DELETE FROM t3; SELECT total_changes(); } } [list $nTotalChange [expr $nTotalChange+2]] finish_test |