Update sqlite3_changes() to match the documentation and add

sqlite3_total_changes(). (CVS 1645)

FossilOrigin-Name: ae2f4a0943854fedbbb6fab1dc3aaf972722ed95
This commit is contained in:
danielk1977 2004-06-21 06:50:26 +00:00
parent d664d9a2bb
commit b28af71a22
20 changed files with 279 additions and 216 deletions

View File

@ -1,5 +1,5 @@
C fix\sfulltest\serror\sby\srestoring\sunset\s(CVS\s1644) C Update\ssqlite3_changes()\sto\smatch\sthe\sdocumentation\sand\sadd\nsqlite3_total_changes().\s(CVS\s1645)
D 2004-06-20T03:06:18 D 2004-06-21T06:50:27
F Makefile.in d69d53c543518c1572ee0a8e8723d7e00bdb2266 F Makefile.in d69d53c543518c1572ee0a8e8723d7e00bdb2266
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -30,15 +30,15 @@ F src/btree.c 0cf8a52a57a7eb13d50719114ee1fa353e89d7d3
F src/btree.h 32f96abef464cf8765b23ca669acfe90d191fcc5 F src/btree.h 32f96abef464cf8765b23ca669acfe90d191fcc5
F src/build.c 2ed1f14a72ce94a2e4adf333272d67a49925304b F src/build.c 2ed1f14a72ce94a2e4adf333272d67a49925304b
F src/date.c b3e8b2bef1e3f2ce24e5b057203036defb18c3f1 F src/date.c b3e8b2bef1e3f2ce24e5b057203036defb18c3f1
F src/delete.c a5191011b7429dff939df631b8bdcc1714b8d7aa F src/delete.c 19287dd204569519636a04eca2b66c49c26e9266
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
F src/expr.c 9ae0e55a230802da35a55fd6e87533cca0301af9 F src/expr.c 9ae0e55a230802da35a55fd6e87533cca0301af9
F src/func.c e520c64e83b4a3fb93668552891124b453cc0eff F src/func.c 3d32878eeb4c6a9977c72ec19984d329b6954c7e
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
F src/insert.c 1428887f4a7515a7d34e82aaeb76297c79ba378b F src/insert.c d99ffe87e1e1397f4233afcd06841d52d6b17b18
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
F src/main.c 96387fc23db30d7ce64f62e95a229c3dd9aff397 F src/main.c b4cd665e7e0af8f47b523e116e3356d0ebf6cef0
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
F src/os.h 1cb5f0293a30288451fe3c0c73815cf208212ed1 F src/os.h 1cb5f0293a30288451fe3c0c73815cf208212ed1
F src/os_common.h ba1b7306e16e2091718f2c48db0fe6c1d7a31bb8 F src/os_common.h ba1b7306e16e2091718f2c48db0fe6c1d7a31bb8
@ -56,26 +56,26 @@ F src/printf.c 823b6a5cbedb6971a9e62f5d83204fe9b0be7c1b
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 9aa82bbc63983a304bc51d4a7c259e759f92c8dc F src/select.c 9aa82bbc63983a304bc51d4a7c259e759f92c8dc
F src/shell.c 24b641700c9d90f361fcfa4f432c5b4aff704e6d F src/shell.c 24b641700c9d90f361fcfa4f432c5b4aff704e6d
F src/sqlite.h.in c34414b9f5330f875e26a69fe685e38ca45f11b9 F src/sqlite.h.in a3d593016d1a1a514d7a26c8a353b58caf62e798
F src/sqliteInt.h 421687a0b3111d4b3df058aa1a5400739d3d3584 F src/sqliteInt.h 0d2e3647c0c881826eb07430cd3745c1fee03c27
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
F src/tclsqlite.c ddef9b18271fb46344d3d35446bd7c001465a69a F src/tclsqlite.c 8d093146332b2f0cbf2a8ebe8597d481619308a3
F src/test1.c ee426e026ad9223483e7a84bb68849fc6e9f542e F src/test1.c ee426e026ad9223483e7a84bb68849fc6e9f542e
F src/test2.c db0a0c30b59f1639cb8c2572be06439402833cc8 F src/test2.c db0a0c30b59f1639cb8c2572be06439402833cc8
F src/test3.c 7247090d15a5a43823079b6fd8dad1ed3cccdedf F src/test3.c 7247090d15a5a43823079b6fd8dad1ed3cccdedf
F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2 F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
F src/test5.c 1b7c275b2929dbd034a567255d2aca339410d1d6 F src/test5.c 1b7c275b2929dbd034a567255d2aca339410d1d6
F src/tokenize.c 900374b6b37f04748bcd48c2d29a41c251542935 F src/tokenize.c 900374b6b37f04748bcd48c2d29a41c251542935
F src/trigger.c fb38c34d933f32dbb6c31b48935f33d868cc7658 F src/trigger.c 65fa572487f945d3d11ab451f232b430a370bae3
F src/update.c f9a03233577e0c3d57234d1957963875fc941da2 F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a
F src/utf.c 3a2596013e4b9582d075ca742de7f067ff7dee95 F src/utf.c 3a2596013e4b9582d075ca742de7f067ff7dee95
F src/util.c 1b3743413e11cae51a899dc03fa9b829a3a1f160 F src/util.c 1b3743413e11cae51a899dc03fa9b829a3a1f160
F src/vacuum.c fcb930215a3f6c50087300782555f61ad11dd80c F src/vacuum.c fcb930215a3f6c50087300782555f61ad11dd80c
F src/vdbe.c 3931b2e4dfb23c8808fb4efc4880dda08c8915ad F src/vdbe.c d8e533a537997ddfdf224cc802abaf3aa4448c69
F src/vdbe.h 9ad64674c4c7acd6744174cab5d34013413ef0d3 F src/vdbe.h 05edb8ec5c038e4ea22827350ee75fb20f0dfddf
F src/vdbeInt.h d007ccada5e3043816097242a560ed6c7f6483ce F src/vdbeInt.h 4d56da610923efa8d4c9db89dff17cb721e69a9b
F src/vdbeapi.c 8a9421341e09b506a934132c9015f26362ae8c0e F src/vdbeapi.c 8a9421341e09b506a934132c9015f26362ae8c0e
F src/vdbeaux.c d2d95f1b9341bd3861e5229cb24a821715824449 F src/vdbeaux.c fa9f0b179a7df3ce3ef42178ec67ace1c9a68e75
F src/vdbemem.c 9359c53386e070fea9f5403cab0c6f0cfe36496b F src/vdbemem.c 9359c53386e070fea9f5403cab0c6f0cfe36496b
F src/where.c 6507074d8ce3f78e7a4cd33f667f11e62020553e F src/where.c 6507074d8ce3f78e7a4cd33f667f11e62020553e
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
@ -93,7 +93,7 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293 F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293
F test/capi2.test 7a0d71b27cfc5337ec3525c02b9de269b5b9c175 F test/capi2.test 7ff5ef9efee9f5ad1945e5f80791a7469ae1a040
F test/capi3.test 6528034f21c4e8e404032124cb58b14ce934598c F test/capi3.test 6528034f21c4e8e404032124cb58b14ce934598c
F test/collate1.test 2ee4fa3a47a652ccf56c5ddf65dcc44d9bad82ef F test/collate1.test 2ee4fa3a47a652ccf56c5ddf65dcc44d9bad82ef
F test/collate2.test c1a3b41f761b28853c5696037f92de928f93233b F test/collate2.test c1a3b41f761b28853c5696037f92de928f93233b
@ -101,7 +101,7 @@ F test/collate3.test e60b428e07ec945492ba90ff1c895902ee3a8a50
F test/collate4.test 0e9fc08ffcf6eddf72e354a15de06688fa86db31 F test/collate4.test 0e9fc08ffcf6eddf72e354a15de06688fa86db31
F test/collate5.test 1dd5f0f508c46667f9d4606c7950c414b0bdc0d5 F test/collate5.test 1dd5f0f508c46667f9d4606c7950c414b0bdc0d5
F test/collate6.test 2a45768914f04c1447a69d1358bbede376552675 F test/collate6.test 2a45768914f04c1447a69d1358bbede376552675
F test/conflict.test 45ce1e44ea748944aed233df8c278a9e1c4c87cc F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d
F test/delete.test 4f0c86e2bebdc822d179c80697b1ceabe6bbcd07 F test/delete.test 4f0c86e2bebdc822d179c80697b1ceabe6bbcd07
@ -114,14 +114,14 @@ F test/hook.test c4102c672d67f8fb60ea459842805abcba69a747
F test/in.test b92a2df9162e1cbd33c6449a29a05e6955b1741a F test/in.test b92a2df9162e1cbd33c6449a29a05e6955b1741a
F test/index.test b6941dd532815f278042b85f79b1a6dc16c4d729 F test/index.test b6941dd532815f278042b85f79b1a6dc16c4d729
F test/insert.test ebbab63db4ad69395a058514bccb3cdb0a029d48 F test/insert.test ebbab63db4ad69395a058514bccb3cdb0a029d48
F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f F test/insert2.test ea5d4f8dcbc68d8ad85eaa5f03d9812757610f90
F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91 F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91
F test/intpkey.test e6e0d7cca0e64ec09cbf683a4712ed2196073742 F test/intpkey.test e6e0d7cca0e64ec09cbf683a4712ed2196073742
F test/ioerr.test 7d087bfd1a1a53442940e000df936e0df0c5b886 F test/ioerr.test 7d087bfd1a1a53442940e000df936e0df0c5b886
F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd
F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718 F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718
F test/laststmtchanges.test cabd11bdfbaf73a4486c50b58297d9c2038ccc18 F test/laststmtchanges.test 417aa27eb2b5cdfafb46e390e2c9ddd0a20eba43
F test/limit.test 60d7f856ee7846f7130dee67f10f0e726cd70b5d F test/limit.test 60d7f856ee7846f7130dee67f10f0e726cd70b5d
F test/lock.test 1dbf1d06b0a7eb36237b4f107cfb3da9726b449e F test/lock.test 1dbf1d06b0a7eb36237b4f107cfb3da9726b449e
F test/main.test e8c4d9ca6d1e5f5e55e6550d31aec488883b2ed9 F test/main.test e8c4d9ca6d1e5f5e55e6550d31aec488883b2ed9
@ -153,7 +153,7 @@ F test/sort.test dbd94673b05054e44ca3f08a80faa1e890ef06d8
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
F test/table.test 06c077c82d1a0df45426518064e674d97def6485 F test/table.test 06c077c82d1a0df45426518064e674d97def6485
F test/tableapi.test b21ab097e87a5484bb61029e69e1a4e5c5e65ede F test/tableapi.test b21ab097e87a5484bb61029e69e1a4e5c5e65ede
F test/tclsqlite.test a69e99b995c913dde3e554da8b3f8f483715fdd3 F test/tclsqlite.test 2517b10ee2c806fb700548f54540aec7d62ed14a
F test/temptable.test 63a16e3ad19adf073cfbcdf7624c92ac5236522c F test/temptable.test 63a16e3ad19adf073cfbcdf7624c92ac5236522c
F test/tester.tcl f36cc22d0532725073ca78272d7834d56dceb6d9 F test/tester.tcl f36cc22d0532725073ca78272d7834d56dceb6d9
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
@ -225,7 +225,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/version3.tcl af528563442e3039928f9018327a18157e53a44f F www/version3.tcl af528563442e3039928f9018327a18157e53a44f
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P fc3b3a8fe86980db4de402bb8e85f8f739fc3883 P d2ccac9d01994de09a195d71cb63d1bf9fb0d33f
R 306731b1d3a316b30d565222feb5ad7f R 2dec0579dc0c3cd8d98bed6d72c511bb
U dougcurrie U danielk1977
Z ad297936c1c1ca71d55b605ccce1a407 Z 2ddd8a9b96a59cb5f116b91751ad2717

View File

@ -1 +1 @@
d2ccac9d01994de09a195d71cb63d1bf9fb0d33f ae2f4a0943854fedbbb6fab1dc3aaf972722ed95

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements. ** to handle DELETE FROM statements.
** **
** $Id: delete.c,v 1.75 2004/06/17 07:53:02 danielk1977 Exp $ ** $Id: delete.c,v 1.76 2004/06/21 06:50:27 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -142,6 +142,7 @@ void sqlite3DeleteFrom(
if( v==0 ){ if( v==0 ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb); sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
/* If we are trying to delete from a view, construct that view into /* If we are trying to delete from a view, construct that view into
@ -271,7 +272,7 @@ void sqlite3DeleteFrom(
} }
/* Delete the row */ /* Delete the row */
sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0); sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
} }
/* If there are row triggers, close all cursors then invoke /* If there are row triggers, close all cursors then invoke
@ -303,7 +304,6 @@ void sqlite3DeleteFrom(
pParse->nTab = iCur; pParse->nTab = iCur;
} }
} }
sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
sqlite3EndWriteOperation(pParse); sqlite3EndWriteOperation(pParse);
/* /*
@ -352,8 +352,7 @@ void sqlite3GenerateRowDelete(
int addr; int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0); sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
(count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
} }

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: func.c,v 1.74 2004/06/19 17:33:07 drh Exp $ ** $Id: func.c,v 1.75 2004/06/21 06:50:28 danielk1977 Exp $
*/ */
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
@ -273,10 +273,10 @@ static void last_insert_rowid(
} }
/* /*
** Implementation of the change_count() SQL function. The return ** Implementation of the changes() SQL function. The return value is the
** value is the same as the sqlite3_changes() API function. ** same as the sqlite3_changes() API function.
*/ */
static void change_count( static void changes(
sqlite3_context *context, sqlite3_context *context,
int arg, int arg,
sqlite3_value **argv sqlite3_value **argv
@ -286,19 +286,20 @@ static void change_count(
} }
/* /*
** Implementation of the last_statement_change_count() SQL function. The ** Implementation of the total_changes() SQL function. The return value is
** return value is the same as the sqlite3_last_statement_changes() API ** the same as the sqlite3_total_changes() API function.
** function.
*/ */
static void last_statement_change_count( static void total_changes(
sqlite3_context *context, sqlite3_context *context,
int arg, int arg,
sqlite3_value **argv sqlite3_value **argv
){ ){
sqlite *db = sqlite3_user_data(context); sqlite *db = sqlite3_user_data(context);
sqlite3_result_int(context, sqlite3_last_statement_changes(db)); sqlite3_result_int(context, sqlite3_total_changes(db));
} }
#if 0
/* /*
** A LIKE pattern compiles to an instance of the following structure. Refer ** A LIKE pattern compiles to an instance of the following structure. Refer
** to the comment for compileLike() function for details. ** to the comment for compileLike() function for details.
@ -315,9 +316,6 @@ typedef struct LikePattern LikePattern;
void deleteLike(void *pLike){ void deleteLike(void *pLike){
sqliteFree(pLike); sqliteFree(pLike);
} }
#if 0
/* #define TRACE_LIKE */ /* #define TRACE_LIKE */
#if defined(TRACE_LIKE) && !defined(NDEBUG) #if defined(TRACE_LIKE) && !defined(NDEBUG)
char *dumpLike(LikePattern *pLike){ char *dumpLike(LikePattern *pLike){
@ -1041,9 +1039,8 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc}, { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc }, { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
{ "change_count", 0, 1, SQLITE_UTF8, 0, change_count }, { "changes", 0, 1, SQLITE_UTF8, 0, changes },
{ "last_statement_change_count", 0, 1, SQLITE_UTF8, 0, { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
last_statement_change_count },
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif #endif

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite. ** to handle INSERT statements in SQLite.
** **
** $Id: insert.c,v 1.112 2004/06/17 07:53:03 danielk1977 Exp $ ** $Id: insert.c,v 1.113 2004/06/21 06:50:28 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -245,6 +245,7 @@ void sqlite3Insert(
*/ */
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup; if( v==0 ) goto insert_cleanup;
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb); sqlite3BeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
/* if there are row triggers, allocate a temp table for new.* references. */ /* if there are row triggers, allocate a temp table for new.* references. */
@ -617,7 +618,6 @@ void sqlite3Insert(
} }
} }
sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
sqlite3EndWriteOperation(pParse); sqlite3EndWriteOperation(pParse);
/* /*
@ -967,6 +967,7 @@ void sqlite3CompleteInsertion(
Vdbe *v; Vdbe *v;
int nIdx; int nIdx;
Index *pIdx; Index *pIdx;
int pik_flags;
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
assert( v!=0 ); assert( v!=0 );
@ -983,9 +984,9 @@ void sqlite3CompleteInsertion(
sqlite3VdbeAddOp(v, OP_Dup, 1, 0); sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0); sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
} }
sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
(pParse->trigStack?0:OPFLAG_NCHANGE) | sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags);
(isUpdate?0:OPFLAG_LASTROWID) | OPFLAG_CSCHANGE);
if( isUpdate && recnoChng ){ if( isUpdate && recnoChng ){
sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
} }

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.230 2004/06/19 09:35:37 danielk1977 Exp $ ** $Id: main.c,v 1.231 2004/06/21 06:50:28 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@ -448,13 +448,10 @@ int sqlite3_changes(sqlite *db){
} }
/* /*
** Return the number of changes produced by the last INSERT, UPDATE, or ** Return the number of changes since the database handle was opened.
** DELETE statement to complete execution. The count does not include
** changes due to SQL statements executed in trigger programs that were
** triggered by that statement
*/ */
int sqlite3_last_statement_changes(sqlite *db){ int sqlite3_total_changes(sqlite3 *db){
return db->lsChange; return db->nTotalChange;
} }
/* /*
@ -952,7 +949,6 @@ int sqlite3_prepare(
goto prepare_out; goto prepare_out;
} }
if( db->pVdbe==0 ){ db->nChange = 0; }
memset(&sParse, 0, sizeof(sParse)); memset(&sParse, 0, sizeof(sParse));
sParse.db = db; sParse.db = db;
sqlite3RunParser(&sParse, zSql, &zErrMsg); sqlite3RunParser(&sParse, zSql, &zErrMsg);

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** presents to client programs.
** **
** @(#) $Id: sqlite.h.in,v 1.104 2004/06/19 08:18:16 danielk1977 Exp $ ** @(#) $Id: sqlite.h.in,v 1.105 2004/06/21 06:50:28 danielk1977 Exp $
*/ */
#ifndef _SQLITE_H_ #ifndef _SQLITE_H_
#define _SQLITE_H_ #define _SQLITE_H_
@ -177,18 +177,12 @@ long long int sqlite3_last_insert_rowid(sqlite3*);
int sqlite3_changes(sqlite3*); int sqlite3_changes(sqlite3*);
/* /*
** This function returns the number of database rows that were changed ** This function returns the number of database rows that have been
** by the last INSERT, UPDATE, or DELETE statment executed by sqlite3_exec(), ** modified by INSERT, UPDATE or DELETE statements since the database handle
** or by the last VM to run to completion. The change count is not updated ** was opened. This includes UPDATE, INSERT and DELETE statements executed
** by SQL statements other than INSERT, UPDATE or DELETE. ** as part of trigger programs. All changes are counted as soon as the
** ** statement that makes them is completed (when the statement handle is
** Changes are counted, even if they are later undone by a ROLLBACK or ** passed to sqlite3_reset() or sqlite_finalise()).
** ABORT. Changes associated with trigger programs that execute as a
** result of the INSERT, UPDATE, or DELETE statement are not counted.
**
** If a callback invokes sqlite3_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 ** SQLite implements the command "DELETE FROM table" without a WHERE clause
** by dropping and recreating the table. (This is much faster than going ** by dropping and recreating the table. (This is much faster than going
@ -197,10 +191,28 @@ int sqlite3_changes(sqlite3*);
** zero regardless of the number of elements that were originally in the ** 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 ** table. To get an accurate count of the number of rows deleted, use
** "DELETE FROM table WHERE 1" instead. ** "DELETE FROM table WHERE 1" instead.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/ */
int sqlite3_last_statement_changes(sqlite3*); int sqlite3_total_changes(sqlite3*);
/*
** This function returns the number of database rows that were changed
** by the last INSERT, UPDATE, or DELETE statment completed. The change
** count is not updated by SQL statements other than INSERT, UPDATE or
** DELETE.
**
** Changes are counted, even if they are later undone by a ROLLBACK or
** ABORT. Changes associated with trigger programs that execute as a
** result of the INSERT, UPDATE, or DELETE statement are not counted.
**
** 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 sqlite3_changes(sqlite3*);
/* This function causes any pending database operation to abort and /* This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically ** return at its earliest opportunity. This routine is typically

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.295 2004/06/19 16:06:12 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.296 2004/06/21 06:50:28 danielk1977 Exp $
*/ */
#include "config.h" #include "config.h"
#include "sqlite3.h" #include "sqlite3.h"
@ -318,16 +318,6 @@ struct Db {
#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
#define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */
#if 0
/*
** Possible values for the Db.textEnc field.
*/
#define TEXT_Utf8 1
#define TEXT_Utf16le 2
#define TEXT_Utf16be 3
#define TEXT_Utf16 (SQLITE_BIGENDIAN?TEXT_Utf16be:TEXT_Utf16le)
#endif
#define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) #define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
/* /*
@ -394,9 +384,8 @@ struct sqlite {
i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 priorNewRowid; /* Last randomly generated ROWID */ i64 priorNewRowid; /* Last randomly generated ROWID */
int magic; /* Magic number for detect library misuse */ int magic; /* Magic number for detect library misuse */
int nChange; /* Number of rows changed (see above) */ int nChange; /* Value returned by sqlite3_changes() */
int lsChange; /* Last statement change count (see above) */ int nTotalChange; /* Value returned by sqlite3_total_changes() */
int csChange; /* Current statement change count (see above) */
struct sqlite3InitInfo { /* Information used during initialization */ struct sqlite3InitInfo { /* Information used during initialization */
int iDb; /* When back is being initialized */ int iDb; /* When back is being initialized */
int newTnum; /* Rootpage of table being initialized */ int newTnum; /* Rootpage of table being initialized */
@ -1050,7 +1039,6 @@ struct AuthContext {
*/ */
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */ #define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */ #define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
#define OPFLAG_CSCHANGE 4 /* Set to update db->csChange */
/* /*
* Each trigger present in the database schema is stored as an instance of * Each trigger present in the database schema is stored as an instance of
@ -1402,6 +1390,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3CheckIndexCollSeq(Parse *, Index *); int sqlite3CheckIndexCollSeq(Parse *, Index *);
int sqlite3CheckObjectName(Parse *, const char *); int sqlite3CheckObjectName(Parse *, const char *);
void sqlite3VdbeSetChanges(sqlite3 *, int);
const void *sqlite3ValueText(sqlite3_value*, u8); const void *sqlite3ValueText(sqlite3_value*, u8);
int sqlite3ValueBytes(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8);

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** A TCL Interface to SQLite ** A TCL Interface to SQLite
** **
** $Id: tclsqlite.c,v 1.89 2004/06/19 08:18:21 danielk1977 Exp $ ** $Id: tclsqlite.c,v 1.90 2004/06/21 06:50:28 danielk1977 Exp $
*/ */
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@ -69,7 +69,6 @@ struct SqliteDb {
SqlFunc *pFunc; /* List of SQL functions */ SqlFunc *pFunc; /* List of SQL functions */
SqlCollate *pCollate; /* List of SQL collation functions */ SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */ int rc; /* Return code of most recent sqlite3_exec() */
int nChange; /* Database changes for the most recent eval */
Tcl_Obj *pCollateNeeded; /* Collation needed script */ Tcl_Obj *pCollateNeeded; /* Collation needed script */
}; };
@ -395,18 +394,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"authorizer", "busy", "changes", "authorizer", "busy", "changes",
"close", "commit_hook", "complete", "close", "commit_hook", "complete",
"errorcode", "eval", "function", "errorcode", "eval", "function",
"last_insert_rowid", "last_statement_changes", "onecolumn", "last_insert_rowid", "onecolumn",
"progress", "rekey", "timeout", "progress", "rekey", "timeout",
"trace", "collate", "collation_needed", "trace", "collate", "collation_needed",
0 "total_changes", 0
}; };
enum DB_enum { enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CHANGES, DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE, DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE,
DB_ERRORCODE, DB_EVAL, DB_FUNCTION, DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN, DB_LAST_INSERT_ROWID, DB_ONECOLUMN,
DB_PROGRESS, DB_REKEY, DB_TIMEOUT, DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
DB_TRACE, DB_COLLATE, DB_COLLATION_NEEDED DB_TRACE, DB_COLLATE, DB_COLLATION_NEEDED,
DB_TOTAL_CHANGES
}; };
if( objc<2 ){ if( objc<2 ){
@ -547,43 +547,20 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/* /* $db changes
** $db changes
** **
** Return the number of rows that were modified, inserted, or deleted by ** Return the number of rows that were modified, inserted, or deleted by
** the most recent "eval". ** the most recent INSERT, UPDATE or DELETE statement, not including
** any changes made by trigger programs.
*/ */
case DB_CHANGES: { case DB_CHANGES: {
Tcl_Obj *pResult; Tcl_Obj *pResult;
int nChange;
if( objc!=2 ){ if( objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, ""); Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR; return TCL_ERROR;
} }
/* nChange = sqlite3_changes(pDb->db); */
nChange = pDb->nChange;
pResult = Tcl_GetObjResult(interp); pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, nChange); Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db));
break;
}
/*
** $db last_statement_changes
**
** Return the number of rows that were modified, inserted, or deleted by
** the last statment to complete execution (excluding changes due to
** triggers)
*/
case DB_LAST_STATEMENT_CHANGES: {
Tcl_Obj *pResult;
int lsChange;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
lsChange = sqlite3_last_statement_changes(pDb->db);
pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, lsChange);
break; break;
} }
@ -685,7 +662,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR; return TCL_ERROR;
} }
pDb->nChange = 0;
zSql = Tcl_GetStringFromObj(objv[2], 0); zSql = Tcl_GetStringFromObj(objv[2], 0);
while( zSql[0] ){ while( zSql[0] ){
int i; int i;
@ -750,7 +726,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
pDb->nChange += sqlite3_changes(pDb->db);
zSql = zLeft; zSql = zLeft;
} }
@ -960,6 +935,23 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; break;
} }
/*
** $db total_changes
**
** Return the number of rows that were modified, inserted, or deleted
** since the database handle was created.
*/
case DB_TOTAL_CHANGES: {
Tcl_Obj *pResult;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
pResult = Tcl_GetObjResult(interp);
Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db));
break;
}
} /* End of the SWITCH statement */ } /* End of the SWITCH statement */
return rc; return rc;
} }

View File

@ -650,28 +650,34 @@ static int codeTriggerProgram(
case TK_UPDATE: { case TK_UPDATE: {
SrcList *pSrc; SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep); pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
sqlite3Update(pParse, pSrc, sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList), sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3ExprDup(pTriggerStep->pWhere), orconf); sqlite3ExprDup(pTriggerStep->pWhere), orconf);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
break; break;
} }
case TK_INSERT: { case TK_INSERT: {
SrcList *pSrc; SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep); pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc, sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList), sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3SelectDup(pTriggerStep->pSelect), sqlite3SelectDup(pTriggerStep->pSelect),
sqlite3IdListDup(pTriggerStep->pIdList), orconf); sqlite3IdListDup(pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
break; break;
} }
case TK_DELETE: { case TK_DELETE: {
SrcList *pSrc; SrcList *pSrc;
sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep); pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere)); sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
break; break;
} }
default: default:

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle UPDATE statements. ** to handle UPDATE statements.
** **
** $Id: update.c,v 1.84 2004/06/16 12:02:52 danielk1977 Exp $ ** $Id: update.c,v 1.85 2004/06/21 06:50:29 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -209,6 +209,7 @@ void sqlite3Update(
*/ */
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup; if( v==0 ) goto update_cleanup;
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb); sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
/* If we are trying to update a view, construct that view into /* If we are trying to update a view, construct that view into
@ -440,7 +441,6 @@ void sqlite3Update(
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0); sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
} }
sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
sqlite3EndWriteOperation(pParse); sqlite3EndWriteOperation(pParse);
/* /*

View File

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** commenting and indentation practices when changing or adding code.
** **
** $Id: vdbe.c,v 1.381 2004/06/19 15:40:23 drh Exp $ ** $Id: vdbe.c,v 1.382 2004/06/21 06:50:29 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@ -3066,11 +3066,9 @@ case OP_NewRecno: {
** be an integer. The stack is popped twice by this instruction. ** be an integer. The stack is popped twice by this instruction.
** **
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not). If the OPFLAG_CSCHANGE flag is set, ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P2 is set,
** then the current statement change count is incremented (otherwise not). ** then rowid is stored for subsequent return by the
** If the OPFLAG_LASTROWID flag of P2 is set, then rowid is ** sqlite3_last_insert_rowid() function (otherwise it's unmodified).
** stored for subsequent return by the sqlite3_last_insert_rowid() function
** (otherwise it's unmodified).
*/ */
/* Opcode: PutStrKey P1 * * /* Opcode: PutStrKey P1 * *
** **
@ -3115,9 +3113,8 @@ case OP_PutStrKey: {
zKey = (char*)&iKey; zKey = (char*)&iKey;
} }
if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i; if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++;
if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){ if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
pC->nextRowidValid = 0; pC->nextRowidValid = 0;
} }
@ -3169,8 +3166,7 @@ case OP_PutStrKey: {
** a record from within an Next loop. ** a record from within an Next loop.
** **
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not). If OPFLAG_CSCHANGE flag is set, ** incremented (otherwise not).
** then the current statement change count is incremented (otherwise not).
** **
** If P1 is a pseudo-table, then this instruction is a no-op. ** If P1 is a pseudo-table, then this instruction is a no-op.
*/ */
@ -3186,19 +3182,22 @@ case OP_Delete: {
pC->nextRowidValid = 0; pC->nextRowidValid = 0;
pC->cacheValid = 0; pC->cacheValid = 0;
} }
if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++;
break; break;
} }
/* Opcode: SetCounts * * * /* Opcode: ResetCount P1 * *
** **
** Called at end of statement. Updates lsChange (last statement change count) ** This opcode resets the VMs internal change counter to 0. If P1 is true,
** and resets csChange (current statement change count) to 0. ** then the value of the change counter is copied to the database handle
** change counter (returned by subsequent calls to sqlite3_changes())
** before it is reset. This is used by trigger programs.
*/ */
case OP_SetCounts: { case OP_ResetCount: {
db->lsChange=db->csChange; if( pOp->p1 ){
db->csChange=0; sqlite3VdbeSetChanges(p->db, p->nChange);
}
p->nChange = 0;
break; break;
} }
@ -3994,9 +3993,12 @@ case OP_ListReset: {
case OP_ListPush: { case OP_ListPush: {
p->keylistStackDepth++; p->keylistStackDepth++;
assert(p->keylistStackDepth > 0); assert(p->keylistStackDepth > 0);
/* FIX ME: This should be allocated at compile time. */
p->keylistStack = sqliteRealloc(p->keylistStack, p->keylistStack = sqliteRealloc(p->keylistStack,
sizeof(Keylist *) * p->keylistStackDepth); sizeof(Keylist *) * p->keylistStackDepth);
if( p->keylistStack==0 ) goto no_mem; if( p->keylistStack==0 ) goto no_mem;
p->keylistStack[p->keylistStackDepth - 1] = p->pList; p->keylistStack[p->keylistStackDepth - 1] = p->pList;
p->pList = 0; p->pList = 0;
break; break;
@ -4028,13 +4030,20 @@ case OP_ListPop: {
*/ */
case OP_ContextPush: { case OP_ContextPush: {
p->contextStackDepth++; p->contextStackDepth++;
assert(p->contextStackDepth > 0); assert( p->contextStackDepth>0 );
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
p->contextStack = sqliteRealloc(p->contextStack, p->contextStack = sqliteRealloc(p->contextStack,
sizeof(Context) * p->contextStackDepth); sizeof(Context) * p->contextStackDepth);
if( p->contextStack==0 ) goto no_mem; if( p->contextStack==0 ) goto no_mem;
p->contextStack[p->contextStackDepth - 1].lastRowid = p->db->lastRowid; p->contextStack[p->contextStackDepth - 1].lastRowid = p->db->lastRowid;
p->contextStack[p->contextStackDepth - 1].nChange = p->nChange;
#if 0
p->contextStack[p->contextStackDepth - 1].lsChange = p->db->lsChange; p->contextStack[p->contextStackDepth - 1].lsChange = p->db->lsChange;
p->contextStack[p->contextStackDepth - 1].csChange = p->db->csChange; p->contextStack[p->contextStackDepth - 1].csChange = p->db->csChange;
#endif
break; break;
} }
@ -4048,8 +4057,11 @@ case OP_ContextPop: {
assert(p->contextStackDepth > 0); assert(p->contextStackDepth > 0);
p->contextStackDepth--; p->contextStackDepth--;
p->db->lastRowid = p->contextStack[p->contextStackDepth].lastRowid; p->db->lastRowid = p->contextStack[p->contextStackDepth].lastRowid;
p->nChange = p->contextStack[p->contextStackDepth].nChange;
#if 0
p->db->lsChange = p->contextStack[p->contextStackDepth].lsChange; p->db->lsChange = p->contextStack[p->contextStackDepth].lsChange;
p->db->csChange = p->contextStack[p->contextStackDepth].csChange; p->db->csChange = p->contextStack[p->contextStackDepth].csChange;
#endif
if( p->contextStackDepth == 0 ){ if( p->contextStackDepth == 0 ){
sqliteFree(p->contextStack); sqliteFree(p->contextStack);
p->contextStack = 0; p->contextStack = 0;

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** simple program to access and modify the underlying database.
** **
** $Id: vdbe.h,v 1.86 2004/06/19 14:49:12 drh Exp $ ** $Id: vdbe.h,v 1.87 2004/06/21 06:50:29 danielk1977 Exp $
*/ */
#ifndef _SQLITE_VDBE_H_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@ -123,6 +123,7 @@ int sqlite3VdbeReset(Vdbe*,char **);
int sqliteVdbeSetVariables(Vdbe*,int,const char**); int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int); void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, const char *, int); int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
#ifndef NDEBUG #ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...); void sqlite3VdbeComment(Vdbe*, const char*, ...);

View File

@ -287,9 +287,8 @@ struct Keylist {
*/ */
typedef struct Context Context; typedef struct Context Context;
struct Context { struct Context {
int lastRowid; /* Last insert rowid (from db->lastRowid) */ int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int lsChange; /* Last statement change count (from db->lsChange) */ int nChange; /* Statement changes (Vdbe.nChanges) */
int csChange; /* Current statement change count (from db->csChange) */
}; };
/* /*
@ -347,6 +346,8 @@ struct Vdbe {
u8 resOnStack; /* True if there are result values on the stack */ u8 resOnStack; /* True if there are result values on the stack */
u8 explain; /* True if EXPLAIN present on SQL command */ u8 explain; /* True if EXPLAIN present on SQL command */
u8 autoCommitOn; /* True if autocommit got turned on by this program */ u8 autoCommitOn; /* True if autocommit got turned on by this program */
int nChange; /* Number of db changes made since last reset */
u8 changeCntOn; /* True to update the change-counter */
}; };
/* /*

View File

@ -645,6 +645,7 @@ void sqlite3VdbeMakeReady(
p->popStack = 0; p->popStack = 0;
p->explain |= isExplain; p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN; p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
#ifdef VDBE_PROFILE #ifdef VDBE_PROFILE
{ {
int i; int i;
@ -1247,6 +1248,15 @@ int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
} }
} }
/* If this was an INSERT, UPDATE or DELETE, set the change counter. */
if( p->changeCntOn ){
if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
sqlite3VdbeSetChanges(db, p->nChange);
}else{
sqlite3VdbeSetChanges(db, 0);
}
p->nChange = 0;
}
if( p->rc!=SQLITE_OK ){ if( p->rc!=SQLITE_OK ){
sqlite3RollbackInternalChanges(db); sqlite3RollbackInternalChanges(db);
@ -1355,7 +1365,6 @@ void sqlite3VdbeDelete(Vdbe *p){
sqliteFree(pOp->p3); sqliteFree(pOp->p3);
} }
if( pOp->p3type==P3_VDBEFUNC ){ if( pOp->p3type==P3_VDBEFUNC ){
int j;
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3; VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
sqlite3VdbeDeleteAuxData(pVdbeFunc, -1); sqlite3VdbeDeleteAuxData(pVdbeFunc, -1);
sqliteFree(pVdbeFunc); sqliteFree(pVdbeFunc);
@ -1755,3 +1764,23 @@ int sqlite3VdbeIdxKeyCompare(
sqlite3VdbeMemRelease(&m); sqlite3VdbeMemRelease(&m);
return SQLITE_OK; return SQLITE_OK;
} }
/*
** This routine sets the value to be returned by subsequent calls to
** sqlite3_changes() on the database handle 'db'.
*/
void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
db->nChange = nChange;
db->nTotalChange += nChange;
}
/*
** Set a flag in the vdbe to update the change counter when it is finalised
** or reset.
*/
void sqlite3VdbeCountChanges(Vdbe *p){
p->changeCntOn = 1;
}

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API. # focus of this script testing the callback-free C/C++ API.
# #
# $Id: capi2.test,v 1.14 2004/06/19 00:16:31 drh Exp $ # $Id: capi2.test,v 1.15 2004/06/21 06:50:29 danielk1977 Exp $
# #
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -227,11 +227,11 @@ do_test capi2-3.10 {
# Update for v3 - the change has not actually happened until the query is # Update for v3 - the change has not actually happened until the query is
# finalized. Is this going to cause trouble for anyone? Lee Nelson maybe? # finalized. Is this going to cause trouble for anyone? Lee Nelson maybe?
do_test capi2-3.10b {sqlite3_changes $DB} {1} do_test capi2-3.10b {db changes} {0}
do_test capi2-3.11 { do_test capi2-3.11 {
sqlite3_finalize $VM sqlite3_finalize $VM
} {SQLITE_OK} } {SQLITE_OK}
do_test capi2-3.11b {sqlite3_changes $DB} {1} do_test capi2-3.11b {db changes} {1}
do_test capi2-3.12 { do_test capi2-3.12 {
sqlite3_finalize $VM sqlite3_finalize $VM
} {SQLITE_MISUSE} } {SQLITE_MISUSE}
@ -242,7 +242,11 @@ do_test capi2-3.13 {
[get_row_values $VM] \ [get_row_values $VM] \
[get_column_names $VM] [get_column_names $VM]
} {SQLITE_ERROR 0 {} {}} } {SQLITE_ERROR 0 {} {}}
do_test capi2-3.13b {db changes} {0}
# Update for v3: Preparing a statement does not affect the change counter.
# (Test result changes from 0 to 1).
do_test capi2-3.13b {db changes} {1}
do_test capi2-3.14 { do_test capi2-3.14 {
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB] list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
} {SQLITE_CONSTRAINT {column a is not unique}} } {SQLITE_CONSTRAINT {column a is not unique}}
@ -602,9 +606,16 @@ do_test capi2-7.10 {
SELECT * FROM t1; SELECT * FROM t1;
} }
} {0 4 1 2 3 2 3 4 3 4 5 4 5 6} } {0 4 1 2 3 2 3 4 3 4 5 4 5 6}
# Update for version 3: A SELECT statement no longer resets the change
# counter (Test result changes from 0 to 4).
do_test capi2-7.11 { do_test capi2-7.11 {
sqlite3_changes $DB sqlite3_changes $DB
} {0} } {4}
do_test capi2-7.11a {
execsql {SELECT count(*) FROM t1}
} {4}
do_test capi2-7.12 { do_test capi2-7.12 {
set x [stepsql $DB {EXPLAIN SELECT * FROM t1}] set x [stepsql $DB {EXPLAIN SELECT * FROM t1}]
lindex $x 0 lindex $x 0

View File

@ -13,7 +13,7 @@
# This file implements tests for the conflict resolution extension # This file implements tests for the conflict resolution extension
# to SQLite. # to SQLite.
# #
# $Id: conflict.test,v 1.21 2004/05/31 08:55:34 danielk1977 Exp $ # $Id: conflict.test,v 1.22 2004/06/21 06:50:29 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -383,9 +383,12 @@ do_test conflict-7.7 {
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
} }
} {1} } {1}
# Update for version 3: A SELECT statement no longer resets the change
# counter (Test result changes from 0 to 50).
do_test conflict-7.7.1 { do_test conflict-7.7.1 {
db changes db changes
} {0} } {50}
# Make sure the row count is right for rows that are ignored on # Make sure the row count is right for rows that are ignored on
# an insert. # an insert.

View File

@ -12,7 +12,7 @@
# focus of this file is testing the INSERT statement that takes is # focus of this file is testing the INSERT statement that takes is
# result from a SELECT. # result from a SELECT.
# #
# $Id: insert2.test,v 1.10 2002/06/25 13:16:04 drh Exp $ # $Id: insert2.test,v 1.11 2004/06/21 06:50:29 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -125,6 +125,7 @@ do_test insert2-3.1 {
} }
} {1 2} } {1 2}
do_test insert2-3.2 { do_test insert2-3.2 {
set x [db total_changes]
execsql { execsql {
BEGIN; BEGIN;
INSERT INTO t4 VALUES(2,4); INSERT INTO t4 VALUES(2,4);
@ -138,7 +139,7 @@ do_test insert2-3.2 {
INSERT INTO t4 VALUES(10,20); INSERT INTO t4 VALUES(10,20);
COMMIT; COMMIT;
} }
db changes expr [db total_changes] - $x
} {9} } {9}
do_test insert2-3.2.1 { do_test insert2-3.2.1 {
execsql { execsql {

View File

@ -7,16 +7,17 @@
# #
#*********************************************************************** #***********************************************************************
# #
# Tests to make sure that value returned by last_statement_change_count() # Tests to make sure that values returned by changes() and total_changes()
# (LSCC) is updated properly, especially inside triggers # are updated properly, especially inside triggers
# #
# Note 1: LSCC remains constant within a statement and only updates once # Note 1: changes() remains constant within a statement and only updates
# the statement is finished (triggers count as part of statement) # once the statement is finished (triggers count as part of
# Note 2: LSCC is changed within the context of a trigger # statement).
# much like last_insert_rowid() (see lastinsert.test), # Note 2: changes() is changed within the context of a trigger much like
# but is restored once the trigger exits # last_insert_rowid() (see lastinsert.test), but is restored once
# Note 3: LSCC is not changed by a change to a view (since everything # the trigger exits.
# is done within instead of trigger context) # 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] set testdir [file dirname $argv0]
@ -25,7 +26,7 @@ source $testdir/tester.tcl
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# 1.x - basic tests (no triggers) # 1.x - basic tests (no triggers)
# LSCC set properly after insert # changes() set properly after insert
do_test laststmtchanges-1.1 { do_test laststmtchanges-1.1 {
catchsql { catchsql {
create table t0 (x); create table t0 (x);
@ -37,100 +38,112 @@ do_test laststmtchanges-1.1 {
insert into t0 values (1); insert into t0 values (1);
insert into t0 values (1); insert into t0 values (1);
insert into t0 values (2); insert into t0 values (2);
select last_statement_change_count(); select changes(), total_changes();
} }
} {0 1} } {0 {1 8}}
# LSCC set properly after update # changes() set properly after update
do_test laststmtchanges-1.2 { do_test laststmtchanges-1.2 {
catchsql { catchsql {
update t0 set x=3 where x=1; update t0 set x=3 where x=1;
select last_statement_change_count(); select changes(), total_changes();
} }
} {0 5} } {0 {5 13}}
# LSCC unchanged within an update statement # changes() unchanged within an update statement
do_test laststmtchanges-1.3 { do_test laststmtchanges-1.3 {
catchsql { catchsql {
update t0 set x=x+last_statement_change_count() where x=3; update t0 set x=x+changes() where x=3;
select count() from t0 where x=8; select count() from t0 where x=8;
} }
} {0 5} } {0 5}
# LSCC set properly after update on table where no rows changed # changes() set properly after update on table where no rows changed
do_test laststmtchanges-1.4 { do_test laststmtchanges-1.4 {
catchsql { catchsql {
update t0 set x=77 where x=88; update t0 set x=77 where x=88;
select last_statement_change_count(); select changes();
} }
} {0 0} } {0 0}
# LSCC set properly after delete from table # changes() set properly after delete from table
do_test laststmtchanges-1.5 { do_test laststmtchanges-1.5 {
catchsql { catchsql {
delete from t0 where x=2; delete from t0 where x=2;
select last_statement_change_count(); select changes();
} }
} {0 3} } {0 3}
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# 2.x - tests with after insert trigger # 2.x - tests with after insert trigger
# LSCC changed properly after insert into table containing after trigger # changes() changed properly after insert into table containing after trigger
do_test laststmtchanges-2.1 { do_test laststmtchanges-2.1 {
set ::tc [db total_changes]
catchsql { catchsql {
create table t1 (k integer primary key); create table t1 (k integer primary key);
create table t2 (k integer primary key, v1, v2); create table t2 (k integer primary key, v1, v2);
create trigger r1 after insert on t1 for each row begin create trigger r1 after insert on t1 for each row begin
insert into t2 values (NULL, last_statement_change_count(), NULL); insert into t2 values (NULL, changes(), NULL);
update t0 set x=x; update t0 set x=x;
update t2 set v2=last_statement_change_count(); update t2 set v2=changes();
end; end;
insert into t1 values (77); insert into t1 values (77);
select last_statement_change_count(); select changes();
} }
} {0 1} } {0 1}
# LSCC unchanged upon entry into after insert trigger # changes() unchanged upon entry into after insert trigger
do_test laststmtchanges-2.2 { do_test laststmtchanges-2.2 {
catchsql { catchsql {
select v1 from t2; select v1 from t2;
} }
} {0 3} } {0 3}
# LSCC changed properly by update within context of after insert trigger # changes() changed properly by update within context of after insert trigger
do_test laststmtchanges-2.3 { do_test laststmtchanges-2.3 {
catchsql { catchsql {
select v2 from t2; select v2 from t2;
} }
} {0 5} } {0 5}
# Total changes caused by firing the trigger above:
#
# 1 from "insert into t1 values(77)" +
# 1 from "insert into t2 values (NULL, changes(), NULL);" +
# 5 from "update t0 set x=x;" +
# 1 from "update t2 set v2=changes();"
#
do_test laststmtchanges-2.4 {
expr [db total_changes] - $::tc
} {8}
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# 3.x - tests with after update trigger # 3.x - tests with after update trigger
# LSCC changed properly after update into table containing after trigger # changes() changed properly after update into table containing after trigger
do_test laststmtchanges-3.1 { do_test laststmtchanges-3.1 {
catchsql { catchsql {
drop trigger r1; drop trigger r1;
delete from t2; delete from t2; delete from t2; delete from t2;
create trigger r1 after update on t1 for each row begin create trigger r1 after update on t1 for each row begin
insert into t2 values (NULL, last_statement_change_count(), NULL); insert into t2 values (NULL, changes(), NULL);
delete from t0 where oid=1 or oid=2; delete from t0 where oid=1 or oid=2;
update t2 set v2=last_statement_change_count(); update t2 set v2=changes();
end; end;
update t1 set k=k; update t1 set k=k;
select last_statement_change_count(); select changes();
} }
} {0 1} } {0 1}
# LSCC unchanged upon entry into after update trigger # changes() unchanged upon entry into after update trigger
do_test laststmtchanges-3.2 { do_test laststmtchanges-3.2 {
catchsql { catchsql {
select v1 from t2; select v1 from t2;
} }
} {0 0} } {0 0}
# LSCC changed properly by delete within context of after update trigger # changes() changed properly by delete within context of after update trigger
do_test laststmtchanges-3.3 { do_test laststmtchanges-3.3 {
catchsql { catchsql {
select v2 from t2; select v2 from t2;
@ -140,29 +153,29 @@ do_test laststmtchanges-3.3 {
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# 4.x - tests with before delete trigger # 4.x - tests with before delete trigger
# LSCC changed properly on delete from table containing before trigger # changes() changed properly on delete from table containing before trigger
do_test laststmtchanges-4.1 { do_test laststmtchanges-4.1 {
catchsql { catchsql {
drop trigger r1; drop trigger r1;
delete from t2; delete from t2; delete from t2; delete from t2;
create trigger r1 before delete on t1 for each row begin create trigger r1 before delete on t1 for each row begin
insert into t2 values (NULL, last_statement_change_count(), NULL); insert into t2 values (NULL, changes(), NULL);
insert into t0 values (5); insert into t0 values (5);
update t2 set v2=last_statement_change_count(); update t2 set v2=changes();
end; end;
delete from t1; delete from t1;
select last_statement_change_count(); select changes();
} }
} {0 1} } {0 1}
# LSCC unchanged upon entry into before delete trigger # changes() unchanged upon entry into before delete trigger
do_test laststmtchanges-4.2 { do_test laststmtchanges-4.2 {
catchsql { catchsql {
select v1 from t2; select v1 from t2;
} }
} {0 0} } {0 0}
# LSCC changed properly by insert within context of before delete trigger # changes() changed properly by insert within context of before delete trigger
do_test laststmtchanges-4.3 { do_test laststmtchanges-4.3 {
catchsql { catchsql {
select v2 from t2; select v2 from t2;
@ -191,40 +204,40 @@ do_test laststmtchanges-5.1 {
insert into t0 values (2); insert into t0 values (2);
insert into t0 values (1); insert into t0 values (1);
create temp trigger r1 instead of insert on v1 for each row begin create temp trigger r1 instead of insert on v1 for each row begin
insert into n1 values (NULL, last_statement_change_count()); insert into n1 values (NULL, changes());
update t0 set x=x*10 where x=1; update t0 set x=x*10 where x=1;
insert into n1 values (NULL, last_statement_change_count()); insert into n1 values (NULL, changes());
insert into t1 values (NEW.k); insert into t1 values (NEW.k);
insert into n1 values (NULL, last_statement_change_count()); insert into n1 values (NULL, changes());
update t0 set x=x*10 where x=0; update t0 set x=x*10 where x=0;
insert into v2 values (100+NEW.k); insert into v2 values (100+NEW.k);
insert into n1 values (NULL, last_statement_change_count()); insert into n1 values (NULL, changes());
end; end;
create temp trigger r2 instead of insert on v2 for each row begin create temp trigger r2 instead of insert on v2 for each row begin
insert into n2 values (NULL, last_statement_change_count()); insert into n2 values (NULL, changes());
insert into t2 values (1000+NEW.k); insert into t2 values (1000+NEW.k);
insert into n2 values (NULL, last_statement_change_count()); insert into n2 values (NULL, changes());
update t0 set x=x*100 where x=0; update t0 set x=x*100 where x=0;
insert into n2 values (NULL, last_statement_change_count()); insert into n2 values (NULL, changes());
delete from t0 where x=2; delete from t0 where x=2;
insert into n2 values (NULL, last_statement_change_count()); insert into n2 values (NULL, changes());
end; end;
insert into t1 values (77); insert into t1 values (77);
select last_statement_change_count(); select changes();
} }
} {0 1} } {0 1}
do_test laststmtchanges-5.2 { do_test laststmtchanges-5.2 {
catchsql { catchsql {
delete from t1 where k=88; delete from t1 where k=88;
select last_statement_change_count(); select changes();
} }
} {0 0} } {0 0}
do_test laststmtchanges-5.3 { do_test laststmtchanges-5.3 {
catchsql { catchsql {
insert into v1 values (5); insert into v1 values (5);
select last_statement_change_count(); select changes();
} }
} {0 0} } {0 0}

View File

@ -15,7 +15,7 @@
# interface is pretty well tested. This file contains some addition # interface is pretty well tested. This file contains some addition
# tests for fringe issues that the main test suite does not cover. # tests for fringe issues that the main test suite does not cover.
# #
# $Id: tclsqlite.test,v 1.24 2004/06/19 00:16:31 drh Exp $ # $Id: tclsqlite.test,v 1.25 2004/06/21 06:50:29 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -34,7 +34,7 @@ do_test tcl-1.1 {
do_test tcl-1.2 { do_test tcl-1.2 {
set v [catch {db bogus} msg] set v [catch {db bogus} msg]
lappend v $msg lappend v $msg
} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, last_statement_changes, onecolumn, progress, rekey, timeout, trace, collate, or collation_needed}} } {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, onecolumn, progress, rekey, timeout, trace, collate, collation_needed, or total_changes}}
do_test tcl-1.3 { do_test tcl-1.3 {
execsql {CREATE TABLE t1(a int, b int)} execsql {CREATE TABLE t1(a int, b int)}
execsql {INSERT INTO t1 VALUES(10,20)} execsql {INSERT INTO t1 VALUES(10,20)}