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 {