diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/delete.c | 9 | ||||
-rw-r--r-- | src/insert.c | 6 | ||||
-rw-r--r-- | src/main.c | 12 | ||||
-rw-r--r-- | src/sqlite.h.in | 24 | ||||
-rw-r--r-- | src/sqliteInt.h | 6 | ||||
-rw-r--r-- | src/tclsqlite.c | 27 | ||||
-rw-r--r-- | src/vdbe.c | 28 |
7 files changed, 80 insertions, 32 deletions
diff --git a/src/delete.c b/src/delete.c index 03df82ea2..3f7e0f7ed 100644 --- a/src/delete.c +++ b/src/delete.c @@ -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.29 2002/03/03 18:59:40 drh Exp $ +** $Id: delete.c,v 1.30 2002/04/12 10:08:59 drh Exp $ */ #include "sqliteInt.h" @@ -183,7 +183,7 @@ void sqliteDeleteFrom( } end = sqliteVdbeMakeLabel(v); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); - sqliteGenerateRowDelete(v, pTab, base); + sqliteGenerateRowDelete(v, pTab, base, 1); sqliteVdbeAddOp(v, OP_Goto, 0, addr); sqliteVdbeResolveLabel(v, end); sqliteVdbeAddOp(v, OP_ListReset, 0, 0); @@ -229,11 +229,12 @@ delete_from_cleanup: void sqliteGenerateRowDelete( Vdbe *v, /* Generate code into this VDBE */ Table *pTab, /* Table containing the row to be deleted */ - int base /* Cursor number for the table */ + int base, /* Cursor number for the table */ + int count /* Increment the row change counter */ ){ sqliteVdbeAddOp(v, OP_MoveTo, base, 0); sqliteGenerateRowIndexDelete(v, pTab, base, 0); - sqliteVdbeAddOp(v, OP_Delete, base, 0); + sqliteVdbeAddOp(v, OP_Delete, base, count); } /* diff --git a/src/insert.c b/src/insert.c index 94867c55b..a848ee12b 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.51 2002/04/12 03:55:16 drh Exp $ +** $Id: insert.c,v 1.52 2002/04/12 10:08:59 drh Exp $ */ #include "sqliteInt.h" @@ -526,7 +526,7 @@ void sqliteGenerateConstraintChecks( break; } case OE_Replace: { - sqliteGenerateRowDelete(v, pTab, base); + sqliteGenerateRowDelete(v, pTab, base, 0); if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); @@ -573,7 +573,7 @@ void sqliteCompleteInsertion( sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0); } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); - sqliteVdbeAddOp(v, OP_PutIntKey, base, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, base, 1); if( isUpdate && recnoChng ){ sqliteVdbeAddOp(v, OP_Pop, 1, 0); } diff --git a/src/main.c b/src/main.c index 389507903..c5aa1927c 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.68 2002/03/06 22:01:36 drh Exp $ +** $Id: main.c,v 1.69 2002/04/12 10:08:59 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -422,6 +422,13 @@ int sqlite_last_insert_rowid(sqlite *db){ } /* +** Return the number of changes in the most recent call to sqlite_exec(). +*/ +int sqlite_changes(sqlite *db){ + return db->nChange; +} + +/* ** Close an existing SQLite database */ void sqlite_close(sqlite *db){ @@ -526,6 +533,8 @@ int sqlite_exec( return rc; } } + if( db->recursionDepth==0 ){ db->nChange = 0; } + db->recursionDepth++; memset(&sParse, 0, sizeof(sParse)); sParse.db = db; sParse.pBe = db->pBe; @@ -544,6 +553,7 @@ int sqlite_exec( if( sParse.rc==SQLITE_SCHEMA ){ clearHashTable(db, 1); } + db->recursionDepth--; return sParse.rc; } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 097ce305b..1ba84badb 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.29 2002/03/08 02:12:00 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.30 2002/04/12 10:08:59 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -173,6 +173,28 @@ int sqlite_exec( */ int sqlite_last_insert_rowid(sqlite*); +/* +** This function returns the number of database rows that were changed +** (or inserted or deleted) by the most recent called sqlite_exec(). +** +** All changes are counted, even if they were later undone by a +** ROLLBACK or ABORT. Except, changes associated with creating and +** dropping tables are not counted. +** +** If a callback invokes sqlite_exec() recursively, then the changes +** in the inner, recursive call are counted together with the changes +** in the outer call. +** +** SQLite implements the command "DELETE FROM table" without a WHERE clause +** by dropping and recreating the table. (This is much faster than going +** through and deleting individual elements form the table.) Because of +** this optimization, the change count for "DELETE FROM table" will be +** zero regardless of the number of elements that were originally in the +** table. To get an accurate count of the number of rows deleted, use +** "DELETE FROM table WHERE 1" instead. +*/ +int sqlite_changes(sqlite*); + /* If the parameter to this routine is one of the return value constants ** defined above, then this routine returns a constant text string which ** descripts (in English) the meaning of the return value. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0cb7eaafd..5fcbd4a39 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.104 2002/03/12 23:10:05 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.105 2002/04/12 10:08:59 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -167,6 +167,8 @@ struct sqlite { int lastRowid; /* ROWID of most recent insert */ int priorNewRowid; /* Last randomly generated ROWID */ int onError; /* Default conflict algorithm */ + int nChange; /* Number of rows changed */ + int recursionDepth; /* Number of nested calls to sqlite_exec() */ }; /* @@ -630,7 +632,7 @@ void sqliteCommitTransaction(Parse*); void sqliteRollbackTransaction(Parse*); char *sqlite_mprintf(const char *, ...); int sqliteExprIsConstant(Expr*); -void sqliteGenerateRowDelete(Vdbe*, Table*, int); +void sqliteGenerateRowDelete(Vdbe*, Table*, int, int); void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*); void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index edf947655..045c18d78 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.30 2002/03/11 02:06:13 drh Exp $ +** $Id: tclsqlite.c,v 1.31 2002/04/12 10:08:59 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -268,10 +268,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ SqliteDb *pDb = (SqliteDb*)cd; int choice; static char *DB_optStrs[] = { - "busy", "close", "complete", "eval", "last_insert_rowid", "timeout", 0 + "busy", "changes", "close", "complete", + "eval", "last_insert_rowid", "timeout", 0 }; enum DB_opts { - DB_BUSY, DB_CLOSE, DB_COMPLETE, DB_EVAL, DB_LAST_INSERT_ROWID, DB_TIMEOUT + DB_BUSY, DB_CHANGES, DB_CLOSE, DB_COMPLETE, + DB_EVAL, DB_LAST_INSERT_ROWID, DB_TIMEOUT }; if( objc<2 ){ @@ -320,6 +322,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ break; } + /* + ** $db changes + ** + ** Return the number of rows that were modified, inserted, or deleted by + ** the most recent "eval". + */ + case DB_CHANGES: { + Tcl_Obj *pResult; + int nChange; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + nChange = sqlite_changes(pDb->db); + pResult = Tcl_GetObjResult(interp); + Tcl_SetIntObj(pResult, nChange); + break; + } + /* $db close ** ** Shutdown the database diff --git a/src/vdbe.c b/src/vdbe.c index 467c62728..2c9a35b32 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.137 2002/04/09 03:15:07 drh Exp $ +** $Id: vdbe.c,v 1.138 2002/04/12 10:09:00 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -3155,19 +3155,16 @@ case OP_NewRecno: { ** stack. The key is the next value down on the stack. The key must ** be an integer. The stack is popped twice by this instruction. ** -** If P2==1 then overwriting is prohibited. If a prior entry with -** the same key exists, an SQLITE_CONSTRAINT exception is raised. +** If P2==1 then the row change count is incremented. If P2==0 the +** row change count is unmodified. */ -/* Opcode: PutStrKey P1 P2 * +/* Opcode: PutStrKey P1 * * ** ** Write an entry into the database file P1. A new entry is ** created if it doesn't already exist or the data for an existing ** entry is overwritten. The data is the value on the top of the ** stack. The key is the next value down on the stack. The key must ** be a string. The stack is popped twice by this instruction. -** -** If P2==1 then overwriting is prohibited. If a prior entry with -** the same key exists, an SQLITE_CONSTRAINT exception is raised. */ case OP_PutIntKey: case OP_PutStrKey: { @@ -3188,16 +3185,7 @@ case OP_PutStrKey: { iKey = intToKey(aStack[nos].i); zKey = (char*)&iKey; db->lastRowid = aStack[nos].i; - } - if( pOp->p2 ){ - int res; - rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res); - if( res==0 && rc==SQLITE_OK ){ - rc = SQLITE_CONSTRAINT; - } - if( rc!=SQLITE_OK ){ - goto abort_due_to_error; - } + if( pOp->p2 ) db->nChange++; } rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey, zStack[tos], aStack[tos].n); @@ -3208,7 +3196,7 @@ case OP_PutStrKey: { break; } -/* Opcode: Delete P1 * * +/* Opcode: Delete P1 P2 * ** ** Delete the record at which the P1 cursor is currently pointing. ** @@ -3216,12 +3204,16 @@ case OP_PutStrKey: { ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. Hence it is OK to delete ** a record from within an Next loop. +** +** The row change counter is incremented if P2==1 and is unmodified +** if P2==0. */ case OP_Delete: { int i = pOp->p1; if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){ rc = sqliteBtreeDelete(p->aCsr[i].pCursor); } + if( pOp->p2 ) db->nChange++; break; } |