From c8d30ac10998ef532f368524fc6be4eac81f4a43 Mon Sep 17 00:00:00 2001
From: drh
Date: Fri, 12 Apr 2002 10:08:59 +0000
Subject: [PATCH] Fix for bug #15: Add the sqlite_changes() API function for
retrieving the number of rows that changed in the previous operation. (CVS
526)
FossilOrigin-Name: 6e71493b9dc77d508c3ce90562766789e87e6d80
---
manifest | 36 ++++++++++++++++++------------------
manifest.uuid | 2 +-
src/delete.c | 9 +++++----
src/insert.c | 6 +++---
src/main.c | 12 +++++++++++-
src/sqlite.h.in | 24 +++++++++++++++++++++++-
src/sqliteInt.h | 6 ++++--
src/tclsqlite.c | 27 ++++++++++++++++++++++++---
src/vdbe.c | 28 ++++++++++------------------
test/conflict.test | 29 ++++++++++++++++++++++++++++-
test/insert2.test | 13 ++++++++++++-
test/tclsqlite.test | 4 ++--
www/c_interface.tcl | 20 +++++++++++++++++++-
www/lang.tcl | 4 +++-
www/tclsqlite.tcl | 11 +++++++++--
15 files changed, 172 insertions(+), 59 deletions(-)
diff --git a/manifest b/manifest
index 74e4b8aad3..4666b62ff1 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sfor\sbug\s#16:\sCheck\sfor\sinvalid\sfunctions\sin\sthe\sVALUES\sclause\sof\san\nINSERT\sstatement.\s(CVS\s525)
-D 2002-04-12T03:55:16
+C Fix\sfor\sbug\s#15:\sAdd\sthe\ssqlite_changes()\sAPI\sfunction\sfor\sretrieving\sthe\nnumber\sof\srows\sthat\schanged\sin\sthe\sprevious\soperation.\s(CVS\s526)
+D 2002-04-12T10:08:59
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -23,13 +23,13 @@ F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 7dd7ddc66459982dd0cb9800958c1f8d65a32d9f
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c d01b81f41481e733e27ab2fa8e1bfcc64f24257d
-F src/delete.c 577da499162291c1855f0b304b211bffcf9da945
+F src/delete.c 6a6b8192cdff5e4b083da3bc63de099f3790d01f
F src/expr.c e7a1e22bc2ebcd789f0f8c0db544cf16ad664054
F src/func.c dca9df811298cd0beb3724d40cee348e884352b2
F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
-F src/insert.c 80105ff6a8bdabe8122948b0066fb1914f9b86c7
-F src/main.c b21019084b93fe685a8a25217d01f6958584ae9b
+F src/insert.c 31233f44fc79edbb43523a830e54736a8e222ff4
+F src/main.c df43fe585d2bfb925c837b6822783c0ee3dd6e1c
F src/md5.c b2b1a34fce66ceca97f4e0dabc20be8be7933c92
F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
@@ -41,10 +41,10 @@ F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c 92aef3f69e90dc065d680d88b1f075409e9249bb
F src/shell.c 994ca7c8c40c40a95011812013fbbf9828f5a0e7
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
-F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197
-F src/sqliteInt.h 73e7d0f39a3c11d395fc422986959261bd193eba
+F src/sqlite.h.in ffcacf73b5ed1a4939205d29a704a185758fa6a6
+F src/sqliteInt.h e47ca9267a4c4a98e9f8d90c2df994a18f23d699
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
-F src/tclsqlite.c df847b71b28277f1cfa1ee1e3e51452ffe5a9a26
+F src/tclsqlite.c c9e9039762d9866eae70bf782237d0206a13f57e
F src/test1.c d46ab7a82a9c16a3b1ee363cb4c0f98c5ff65743
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
@@ -52,7 +52,7 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c 5624d342601f616157ba266abccc1368a5afee70
F src/update.c 7dd714a6a7fa47f849ebb36b6d915974d6c6accb
F src/util.c b34cd91387bbfdc79319ea451a7d120cef478120
-F src/vdbe.c ccc394cf72b5c43b71309fecc35cdf5cd252e154
+F src/vdbe.c 9213ff1ab136eabcf3e8a58157765a01274bf8e9
F src/vdbe.h f9be1f6e9a336c3ff4d14ea7489ee976e07460cc
F src/where.c 9d36f6c9fea4af71501770c13089f824cb9b033c
F test/all.test 6aa106eee4d7127afa5cee97c51a783a79694ead
@@ -60,7 +60,7 @@ F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
-F test/conflict.test 3383ac08da14cdba11bb4c9495583cf87f67afb1
+F test/conflict.test 5149646703d3930c9111068b5cda7e2e938476e3
F test/copy.test b3cefcb520c64d7e7dfedbab06b4d4c31fa5b99a
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
F test/expr.test 846795016b5993a7411f772eebe82ab67bd7230a
@@ -68,7 +68,7 @@ F test/func.test d34e461f0acb0cf2978a4b3a3e098460f2ea8fbc
F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa
F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
F test/insert.test c36d534a4ab58c2cd452a273e51b2b0dd1ede1f9
-F test/insert2.test 2f02b1e0dbfba3e8c76496209be5f4010b584181
+F test/insert2.test eb8481878a7f52ccb4e3346f87550f5afdd77f76
F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a
@@ -94,7 +94,7 @@ F test/sort.test 3b996ce7ca385f9cd559944ac0f4027a23aa546b
F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
F test/table.test 17b0b6eafa3faaee5545b7a94e6c1ff73f0880f3
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
-F test/tclsqlite.test ca8dd89b02ab68bd4540163c24551756a69f6783
+F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533
F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
@@ -115,7 +115,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
-F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2
+F www/c_interface.tcl 79f63ffa8c6e7adb9e3449ff325d093cfb0ce3e3
F www/changes.tcl 4083f03195f0ae36411e095a2d18e5fb4a3c40d9
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
@@ -124,14 +124,14 @@ F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/faq.tcl fb1e92e2f604546694f83a36d969492f52fb685d
F www/formatchng.tcl 2ce21ff30663fad6618198fe747ce675df577590
F www/index.tcl 2a9653ebeeaba3aca3401f476ba0e0e4acb40929
-F www/lang.tcl 75615f1acd8a428d93546ad9edfbf8f78ee1e2df
+F www/lang.tcl 2d4654255ad1ec7f58d02dc41b59528c0ee6ea44
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
-F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
+F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P bb83642e9a6c1c9ade861618496933c9f922a8f8
-R f474a54633adfc730f9670e6001e85d7
+P 43a77f019d34e1a6b3f502ad0ec31a00c8fdbe6e
+R f1c51fffab48448616c03a8f7db64a46
U drh
-Z ee5b859e30a1d5d36bceb3c81154e192
+Z fa8a7c3395ff2734ddb7f18394f23f2a
diff --git a/manifest.uuid b/manifest.uuid
index f9104e48d0..88dedaadec 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-43a77f019d34e1a6b3f502ad0ec31a00c8fdbe6e
\ No newline at end of file
+6e71493b9dc77d508c3ce90562766789e87e6d80
\ No newline at end of file
diff --git a/src/delete.c b/src/delete.c
index 03df82ea2e..3f7e0f7edf 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 94867c55bb..a848ee12bb 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 389507903c..c5aa1927c2 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"
@@ -421,6 +421,13 @@ int sqlite_last_insert_rowid(sqlite *db){
return db->lastRowid;
}
+/*
+** 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
*/
@@ -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 097ce305ba..1ba84badbe 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 0cb7eaafdf..5fcbd4a392 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 edf9476554..045c18d788 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 467c627286..2c9a35b32a 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
@@ -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 && inCursor && ) p->aCsr[i].pCursor!=0 ){
rc = sqliteBtreeDelete(p->aCsr[i].pCursor);
}
+ if( pOp->p2 ) db->nChange++;
break;
}
diff --git a/test/conflict.test b/test/conflict.test
index a3f6bee745..8db98e8205 100644
--- a/test/conflict.test
+++ b/test/conflict.test
@@ -13,7 +13,7 @@
# This file implements tests for the conflict resolution extension
# to SQLite.
#
-# $Id: conflict.test,v 1.10 2002/04/09 03:28:01 drh Exp $
+# $Id: conflict.test,v 1.11 2002/04/12 10:09:00 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -399,6 +399,9 @@ do_test conflict-7.2 {
UPDATE OR IGNORE t1 SET a=1000;
}
} {1}
+do_test conflict-7.2.1 {
+ db changes
+} {1}
do_test conflict-7.3 {
execsql {
SELECT b FROM t1 WHERE a=1000;
@@ -415,6 +418,9 @@ do_test conflict-7.5 {
UPDATE OR REPLACE t1 SET a=1001;
}
} {50}
+do_test conflict-7.5.1 {
+ db changes
+} {50}
do_test conflict-7.6 {
execsql {
SELECT b FROM t1 WHERE a=1001;
@@ -425,6 +431,9 @@ do_test conflict-7.7 {
SELECT count(*) FROM t1;
}
} {1}
+do_test conflict-7.7.1 {
+ db changes
+} {0}
# Make sure the row count is right for rows that are ignored on
# an insert.
@@ -438,31 +447,49 @@ do_test conflict-8.1 {
INSERT OR IGNORE INTO t1 VALUES(2,3);
}
} {1}
+do_test conflict-8.1.1 {
+ db changes
+} {1}
do_test conflict-8.2 {
execsql {
INSERT OR IGNORE INTO t1 VALUES(2,4);
}
} {0}
+do_test conflict-8.2.1 {
+ db changes
+} {0}
do_test conflict-8.3 {
execsql {
INSERT OR REPLACE INTO t1 VALUES(2,4);
}
} {1}
+do_test conflict-8.3.1 {
+ db changes
+} {1}
do_test conflict-8.4 {
execsql {
INSERT OR IGNORE INTO t1 SELECT * FROM t1;
}
} {0}
+do_test conflict-8.4.1 {
+ db changes
+} {0}
do_test conflict-8.5 {
execsql {
INSERT OR IGNORE INTO t1 SELECT a+2,b+2 FROM t1;
}
} {2}
+do_test conflict-8.5.1 {
+ db changes
+} {2}
do_test conflict-8.6 {
execsql {
INSERT OR IGNORE INTO t1 SELECT a+3,b+3 FROM t1;
}
} {3}
+do_test conflict-8.6.1 {
+ db changes
+} {3}
do_test insert-99.1 {
set x [execsql {PRAGMA integrity_check}]
diff --git a/test/insert2.test b/test/insert2.test
index fca4865edb..f90c320304 100644
--- a/test/insert2.test
+++ b/test/insert2.test
@@ -12,7 +12,7 @@
# focus of this file is testing the INSERT statement that takes is
# result from a SELECT.
#
-# $Id: insert2.test,v 1.8 2002/03/03 02:49:52 drh Exp $
+# $Id: insert2.test,v 1.9 2002/04/12 10:09:00 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -38,6 +38,9 @@ do_test insert2-1.1.1 {
}
} {6}
do_test insert2-1.1.2 {
+ db changes
+} {6}
+do_test insert2-1.1.3 {
execsql {SELECT * FROM t1 ORDER BY log}
} {0 1 1 1 2 2 3 4 4 8 5 4}
@@ -138,6 +141,11 @@ do_test insert2-3.2 {
INSERT INTO t4 VALUES(9,18);
INSERT INTO t4 VALUES(10,20);
COMMIT;
+ }
+ db changes
+} {9}
+do_test insert2-3.2.1 {
+ execsql {
SELECT count(*) FROM t4;
}
} {10}
@@ -182,5 +190,8 @@ do_test insert2-3.7 {
ROLLBACK;
}
} {1}
+do_test insert2-3.8 {
+ db changes
+} {159}
finish_test
diff --git a/test/tclsqlite.test b/test/tclsqlite.test
index 42ff8d19f0..b8e99b2f32 100644
--- a/test/tclsqlite.test
+++ b/test/tclsqlite.test
@@ -15,7 +15,7 @@
# interface is pretty well tested. This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
-# $Id: tclsqlite.test,v 1.5 2002/01/16 21:00:28 drh Exp $
+# $Id: tclsqlite.test,v 1.6 2002/04/12 10:09:00 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -29,7 +29,7 @@ do_test tcl-1.1 {
do_test tcl-1.2 {
set v [catch {db bogus} msg]
lappend v $msg
-} {1 {bad option "bogus": must be busy, close, complete, eval, last_insert_rowid, or timeout}}
+} {1 {bad option "bogus": must be busy, changes, close, complete, eval, last_insert_rowid, or timeout}}
do_test tcl-1.3 {
execsql {CREATE TABLE t1(a int, b int)}
execsql {INSERT INTO t1 VALUES(10,20)}
diff --git a/www/c_interface.tcl b/www/c_interface.tcl
index 5f2f361745..88afe38f4e 100644
--- a/www/c_interface.tcl
+++ b/www/c_interface.tcl
@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the sqlite.html file.
#
-set rcsid {$Id: c_interface.tcl,v 1.25 2002/03/04 02:26:17 drh Exp $}
+set rcsid {$Id: c_interface.tcl,v 1.26 2002/04/12 10:09:00 drh Exp $}
puts {
@@ -307,6 +307,8 @@ useful interfaces. These extended routines are as follows:
int sqlite_last_insert_rowid(sqlite*);
+int sqlite_changes(sqlite*);
+
int sqlite_get_table(
sqlite*,
char *sql,
@@ -389,6 +391,22 @@ the key is automatically generated. You can find the value of the key
for the most recent INSERT statement using the
sqlite_last_insert_rowid() API function.
+The number of rows that changed
+
+The sqlite_changes() API function returns the number of rows
+that were inserted, deleted, or modified during the most recent
+sqlite_exec() call. The number reported includes any changes
+that were later undo by a ROLLBACK or ABORT. But rows that are
+deleted because of a DROP TABLE are not counted.
+
+SQLite implements the command "DELETE FROM table" (without
+a WHERE clause) by dropping the table then recreating it.
+This is much faster than deleting the elements of the table individually.
+But it also means that the value returned from sqlite_changes()
+will be zero regardless of the number of elements that were originally
+in the table. If an accurate count of the number of elements deleted
+is necessary, use "DELETE FROM table WHERE 1" instead.
+
Querying without using a callback function
The sqlite_get_table() function is a wrapper around
diff --git a/www/lang.tcl b/www/lang.tcl
index be8a820087..b959470cd3 100644
--- a/www/lang.tcl
+++ b/www/lang.tcl
@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the sqlite.html file.
#
-set rcsid {$Id: lang.tcl,v 1.31 2002/04/06 14:10:48 drh Exp $}
+set rcsid {$Id: lang.tcl,v 1.32 2002/04/12 10:09:00 drh Exp $}
puts {
@@ -843,6 +843,8 @@ with caution.
When on, the COUNT_CHANGES pragma causes the callback function to
be invoked once for each DELETE, INSERT, or UPDATE operation. The
argument is the number of rows that were changed.
+ This pragma may be removed from future versions of SQLite.
+ Consider using the sqlite_changes() API function instead.
PRAGMA default_cache_size;
PRAGMA default_cache_size = Number-of-pages;
diff --git a/www/tclsqlite.tcl b/www/tclsqlite.tcl
index f54069885d..862966cd17 100644
--- a/www/tclsqlite.tcl
+++ b/www/tclsqlite.tcl
@@ -1,7 +1,7 @@
#
# Run this Tcl script to generate the tclsqlite.html file.
#
-set rcsid {$Id: tclsqlite.tcl,v 1.6 2002/01/16 21:00:28 drh Exp $}
+set rcsid {$Id: tclsqlite.tcl,v 1.7 2002/04/12 10:09:00 drh Exp $}
puts {
@@ -50,12 +50,13 @@ the database is stored.
Once an SQLite database is open, it can be controlled using
-methods of the dbcmd. There are currently 6 methods
+methods of the dbcmd. There are currently 7 methods
defined:
- busy
+
- changes
- close
- complete
- eval
@@ -248,6 +249,12 @@ should return "1" if it wants SQLite to abandon the current operation.
The "last_insert_rowid" method returns an integer which is the ROWID
of the most recently inserted database row.
+The "changes" method
+
+The "changes" method returns an integer which is the number of rows
+in the database that were inserted, deleted, and/or modified by the most
+recent "eval" method.
+
}
puts {