aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/delete.c9
-rw-r--r--src/insert.c6
-rw-r--r--src/main.c12
-rw-r--r--src/sqlite.h.in24
-rw-r--r--src/sqliteInt.h6
-rw-r--r--src/tclsqlite.c27
-rw-r--r--src/vdbe.c28
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;
}