-C fix\sfulltest\serror\sby\srestoring\sunset\s(CVS\s1644)
-D 2004-06-20T03:06:18
+C Update\ssqlite3_changes()\sto\smatch\sthe\sdocumentation\sand\sadd\nsqlite3_total_changes().\s(CVS\s1645)
+D 2004-06-21T06:50:27
F Makefile.in d69d53c543518c1572ee0a8e8723d7e00bdb2266
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/btree.h 32f96abef464cf8765b23ca669acfe90d191fcc5
F src/build.c 2ed1f14a72ce94a2e4adf333272d67a49925304b
F src/date.c b3e8b2bef1e3f2ce24e5b057203036defb18c3f1
-F src/delete.c a5191011b7429dff939df631b8bdcc1714b8d7aa
+F src/delete.c 19287dd204569519636a04eca2b66c49c26e9266
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
F src/expr.c 9ae0e55a230802da35a55fd6e87533cca0301af9
-F src/func.c e520c64e83b4a3fb93668552891124b453cc0eff
+F src/func.c 3d32878eeb4c6a9977c72ec19984d329b6954c7e
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 1428887f4a7515a7d34e82aaeb76297c79ba378b
+F src/insert.c d99ffe87e1e1397f4233afcd06841d52d6b17b18
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
-F src/main.c 96387fc23db30d7ce64f62e95a229c3dd9aff397
+F src/main.c b4cd665e7e0af8f47b523e116e3356d0ebf6cef0
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
F src/os.h 1cb5f0293a30288451fe3c0c73815cf208212ed1
F src/os_common.h ba1b7306e16e2091718f2c48db0fe6c1d7a31bb8
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 9aa82bbc63983a304bc51d4a7c259e759f92c8dc
F src/shell.c 24b641700c9d90f361fcfa4f432c5b4aff704e6d
-F src/sqlite.h.in c34414b9f5330f875e26a69fe685e38ca45f11b9
-F src/sqliteInt.h 421687a0b3111d4b3df058aa1a5400739d3d3584
+F src/sqlite.h.in a3d593016d1a1a514d7a26c8a353b58caf62e798
+F src/sqliteInt.h 0d2e3647c0c881826eb07430cd3745c1fee03c27
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
-F src/tclsqlite.c ddef9b18271fb46344d3d35446bd7c001465a69a
+F src/tclsqlite.c 8d093146332b2f0cbf2a8ebe8597d481619308a3
F src/test1.c ee426e026ad9223483e7a84bb68849fc6e9f542e
F src/test2.c db0a0c30b59f1639cb8c2572be06439402833cc8
F src/test3.c 7247090d15a5a43823079b6fd8dad1ed3cccdedf
F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
F src/test5.c 1b7c275b2929dbd034a567255d2aca339410d1d6
F src/tokenize.c 900374b6b37f04748bcd48c2d29a41c251542935
-F src/trigger.c fb38c34d933f32dbb6c31b48935f33d868cc7658
-F src/update.c f9a03233577e0c3d57234d1957963875fc941da2
+F src/trigger.c 65fa572487f945d3d11ab451f232b430a370bae3
+F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a
F src/utf.c 3a2596013e4b9582d075ca742de7f067ff7dee95
F src/util.c 1b3743413e11cae51a899dc03fa9b829a3a1f160
F src/vacuum.c fcb930215a3f6c50087300782555f61ad11dd80c
-F src/vdbe.c 3931b2e4dfb23c8808fb4efc4880dda08c8915ad
-F src/vdbe.h 9ad64674c4c7acd6744174cab5d34013413ef0d3
-F src/vdbeInt.h d007ccada5e3043816097242a560ed6c7f6483ce
+F src/vdbe.c d8e533a537997ddfdf224cc802abaf3aa4448c69
+F src/vdbe.h 05edb8ec5c038e4ea22827350ee75fb20f0dfddf
+F src/vdbeInt.h 4d56da610923efa8d4c9db89dff17cb721e69a9b
F src/vdbeapi.c 8a9421341e09b506a934132c9015f26362ae8c0e
-F src/vdbeaux.c d2d95f1b9341bd3861e5229cb24a821715824449
+F src/vdbeaux.c fa9f0b179a7df3ce3ef42178ec67ace1c9a68e75
F src/vdbemem.c 9359c53386e070fea9f5403cab0c6f0cfe36496b
F src/where.c 6507074d8ce3f78e7a4cd33f667f11e62020553e
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293
-F test/capi2.test 7a0d71b27cfc5337ec3525c02b9de269b5b9c175
+F test/capi2.test 7ff5ef9efee9f5ad1945e5f80791a7469ae1a040
F test/capi3.test 6528034f21c4e8e404032124cb58b14ce934598c
F test/collate1.test 2ee4fa3a47a652ccf56c5ddf65dcc44d9bad82ef
F test/collate2.test c1a3b41f761b28853c5696037f92de928f93233b
F test/collate4.test 0e9fc08ffcf6eddf72e354a15de06688fa86db31
F test/collate5.test 1dd5f0f508c46667f9d4606c7950c414b0bdc0d5
F test/collate6.test 2a45768914f04c1447a69d1358bbede376552675
-F test/conflict.test 45ce1e44ea748944aed233df8c278a9e1c4c87cc
+F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d
F test/delete.test 4f0c86e2bebdc822d179c80697b1ceabe6bbcd07
F test/in.test b92a2df9162e1cbd33c6449a29a05e6955b1741a
F test/index.test b6941dd532815f278042b85f79b1a6dc16c4d729
F test/insert.test ebbab63db4ad69395a058514bccb3cdb0a029d48
-F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
+F test/insert2.test ea5d4f8dcbc68d8ad85eaa5f03d9812757610f90
F test/interrupt.test 9142ce4448605127640eda5e283952f75f67ed91
F test/intpkey.test e6e0d7cca0e64ec09cbf683a4712ed2196073742
F test/ioerr.test 7d087bfd1a1a53442940e000df936e0df0c5b886
F test/join.test 9ef6aabaac9de51d5fc41e68d1f4355da05a84cd
F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8
F test/lastinsert.test 31382f88b9b0270333ac9e4a17f2c2f4732da718
-F test/laststmtchanges.test cabd11bdfbaf73a4486c50b58297d9c2038ccc18
+F test/laststmtchanges.test 417aa27eb2b5cdfafb46e390e2c9ddd0a20eba43
F test/limit.test 60d7f856ee7846f7130dee67f10f0e726cd70b5d
F test/lock.test 1dbf1d06b0a7eb36237b4f107cfb3da9726b449e
F test/main.test e8c4d9ca6d1e5f5e55e6550d31aec488883b2ed9
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
F test/table.test 06c077c82d1a0df45426518064e674d97def6485
F test/tableapi.test b21ab097e87a5484bb61029e69e1a4e5c5e65ede
-F test/tclsqlite.test a69e99b995c913dde3e554da8b3f8f483715fdd3
+F test/tclsqlite.test 2517b10ee2c806fb700548f54540aec7d62ed14a
F test/temptable.test 63a16e3ad19adf073cfbcdf7624c92ac5236522c
F test/tester.tcl f36cc22d0532725073ca78272d7834d56dceb6d9
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/version3.tcl af528563442e3039928f9018327a18157e53a44f
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P fc3b3a8fe86980db4de402bb8e85f8f739fc3883
-R 306731b1d3a316b30d565222feb5ad7f
-U dougcurrie
-Z ad297936c1c1ca71d55b605ccce1a407
+P d2ccac9d01994de09a195d71cb63d1bf9fb0d33f
+R 2dec0579dc0c3cd8d98bed6d72c511bb
+U danielk1977
+Z 2ddd8a9b96a59cb5f116b91751ad2717
-d2ccac9d01994de09a195d71cb63d1bf9fb0d33f
\ No newline at end of file
+ae2f4a0943854fedbbb6fab1dc3aaf972722ed95
\ No newline at end of file
** This file contains C code routines that are called by the parser
** 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"
if( v==0 ){
goto delete_from_cleanup;
}
+ sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
/* If we are trying to delete from a view, construct that view into
}
/* 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
pParse->nTab = iCur;
}
}
- sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
sqlite3EndWriteOperation(pParse);
/*
int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Delete, iCur,
- (count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
+ sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
}
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** 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 <math.h>
}
/*
-** Implementation of the change_count() SQL function. The return
-** value is the same as the sqlite3_changes() API function.
+** Implementation of the changes() SQL function. The return value is the
+** same as the sqlite3_changes() API function.
*/
-static void change_count(
+static void changes(
sqlite3_context *context,
int arg,
sqlite3_value **argv
}
/*
-** Implementation of the last_statement_change_count() SQL function. The
-** return value is the same as the sqlite3_last_statement_changes() API
-** function.
+** Implementation of the total_changes() SQL function. The return value is
+** the same as the sqlite3_total_changes() API function.
*/
-static void last_statement_change_count(
- sqlite3_context *context,
+static void total_changes(
+ sqlite3_context *context,
int arg,
sqlite3_value **argv
){
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
** to the comment for compileLike() function for details.
void deleteLike(void *pLike){
sqliteFree(pLike);
}
-
-
-#if 0
/* #define TRACE_LIKE */
#if defined(TRACE_LIKE) && !defined(NDEBUG)
char *dumpLike(LikePattern *pLike){
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
{ "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
- { "change_count", 0, 1, SQLITE_UTF8, 0, change_count },
- { "last_statement_change_count", 0, 1, SQLITE_UTF8, 0,
- last_statement_change_count },
+ { "changes", 0, 1, SQLITE_UTF8, 0, changes },
+ { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
** This file contains C code routines that are called by the parser
** 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"
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
+ sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
/* if there are row triggers, allocate a temp table for new.* references. */
}
}
- sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
sqlite3EndWriteOperation(pParse);
/*
Vdbe *v;
int nIdx;
Index *pIdx;
+ int pik_flags;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
}
- sqlite3VdbeAddOp(v, OP_PutIntKey, base,
- (pParse->trigStack?0:OPFLAG_NCHANGE) |
- (isUpdate?0:OPFLAG_LASTROWID) | OPFLAG_CSCHANGE);
+ pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
+ sqlite3VdbeAddOp(v, OP_PutIntKey, base, pik_flags);
+
if( isUpdate && recnoChng ){
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
}
** other files are for internal use by SQLite and should not be
** 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 "os.h"
}
/*
-** Return the number of changes produced by the last INSERT, UPDATE, or
-** 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
+** Return the number of changes since the database handle was opened.
*/
-int sqlite3_last_statement_changes(sqlite *db){
- return db->lsChange;
+int sqlite3_total_changes(sqlite3 *db){
+ return db->nTotalChange;
}
/*
goto prepare_out;
}
- if( db->pVdbe==0 ){ db->nChange = 0; }
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sqlite3RunParser(&sParse, zSql, &zErrMsg);
** This header file defines the interface that the SQLite library
** 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_
#define _SQLITE_H_
*/
int sqlite3_changes(sqlite3*);
+/*
+** This function returns the number of database rows that have been
+** modified by INSERT, UPDATE or DELETE statements since the database handle
+** was opened. This includes UPDATE, INSERT and DELETE statements executed
+** as part of trigger programs. All changes are counted as soon as the
+** statement that makes them is completed (when the statement handle is
+** passed to sqlite3_reset() or sqlite_finalise()).
+**
+** 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_total_changes(sqlite3*);
+
/*
** This function returns the number of database rows that were changed
-** by the last INSERT, UPDATE, or DELETE statment executed by sqlite3_exec(),
-** or by the last VM to run to completion. The change count is not updated
-** by SQL statements other than INSERT, UPDATE or DELETE.
+** 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.
**
-** 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
** by dropping and recreating the table. (This is much faster than going
** through and deleting individual elements form the table.) Because of
** 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.
-**
-******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
-int sqlite3_last_statement_changes(sqlite3*);
+int sqlite3_changes(sqlite3*);
/* This function causes any pending database operation to abort and
** return at its earliest opportunity. This routine is typically
*************************************************************************
** 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 "sqlite3.h"
#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
#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)
/*
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 priorNewRowid; /* Last randomly generated ROWID */
int magic; /* Magic number for detect library misuse */
- int nChange; /* Number of rows changed (see above) */
- int lsChange; /* Last statement change count (see above) */
- int csChange; /* Current statement change count (see above) */
- struct sqlite3InitInfo { /* Information used during initialization */
- int iDb; /* When back is being initialized */
- int newTnum; /* Rootpage of table being initialized */
- u8 busy; /* TRUE if currently initializing */
+ int nChange; /* Value returned by sqlite3_changes() */
+ int nTotalChange; /* Value returned by sqlite3_total_changes() */
+ struct sqlite3InitInfo { /* Information used during initialization */
+ int iDb; /* When back is being initialized */
+ int newTnum; /* Rootpage of table being initialized */
+ u8 busy; /* TRUE if currently initializing */
} init;
struct Vdbe *pVdbe; /* List of active virtual machines */
int activeVdbeCnt; /* Number of vdbes currently executing */
*/
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
#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
int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3CheckIndexCollSeq(Parse *, Index *);
int sqlite3CheckObjectName(Parse *, const char *);
+void sqlite3VdbeSetChanges(sqlite3 *, int);
const void *sqlite3ValueText(sqlite3_value*, u8);
int sqlite3ValueBytes(sqlite3_value*, u8);
*************************************************************************
** 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 */
SqlFunc *pFunc; /* List of SQL functions */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
- int nChange; /* Database changes for the most recent eval */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
};
"authorizer", "busy", "changes",
"close", "commit_hook", "complete",
"errorcode", "eval", "function",
- "last_insert_rowid", "last_statement_changes", "onecolumn",
+ "last_insert_rowid", "onecolumn",
"progress", "rekey", "timeout",
"trace", "collate", "collation_needed",
- 0
+ "total_changes", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BUSY, DB_CHANGES,
DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE,
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_TRACE, DB_COLLATE, DB_COLLATION_NEEDED
+ DB_TRACE, DB_COLLATE, DB_COLLATION_NEEDED,
+ DB_TOTAL_CHANGES
};
if( objc<2 ){
break;
}
- /*
- ** $db changes
+ /* $db changes
**
** 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: {
Tcl_Obj *pResult;
- int nChange;
- if( objc!=2 ){
- Tcl_WrongNumArgs(interp, 2, objv, "");
- return TCL_ERROR;
- }
- /* nChange = sqlite3_changes(pDb->db); */
- nChange = pDb->nChange;
- pResult = Tcl_GetObjResult(interp);
- Tcl_SetIntObj(pResult, nChange);
- 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);
+ Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db));
break;
}
return TCL_ERROR;
}
- pDb->nChange = 0;
zSql = Tcl_GetStringFromObj(objv[2], 0);
while( zSql[0] ){
int i;
break;
}
- pDb->nChange += sqlite3_changes(pDb->db);
zSql = zLeft;
}
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 */
return rc;
}
case TK_UPDATE: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3ExprDup(pTriggerStep->pWhere), orconf);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
break;
}
case TK_INSERT: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3SelectDup(pTriggerStep->pSelect),
sqlite3IdListDup(pTriggerStep->pIdList), orconf);
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
break;
}
case TK_DELETE: {
SrcList *pSrc;
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 0, 0);
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
sqlite3VdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_ResetCount, 1, 0);
break;
}
default:
** This file contains C code routines that are called by the parser
** 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"
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
+ sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
/* If we are trying to update a view, construct that view into
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
}
- sqlite3VdbeAddOp(v, OP_SetCounts, 0, 0);
sqlite3EndWriteOperation(pParse);
/*
** in this file for details. If in doubt, do not deviate from existing
** 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 "os.h"
** 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
-** incremented (otherwise not). If the OPFLAG_CSCHANGE flag is set,
-** then the current statement change count is incremented (otherwise not).
-** If the OPFLAG_LASTROWID flag of P2 is set, then rowid is
-** stored for subsequent return by the sqlite3_last_insert_rowid() function
-** (otherwise it's unmodified).
+** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P2 is set,
+** then rowid is stored for subsequent return by the
+** sqlite3_last_insert_rowid() function (otherwise it's unmodified).
*/
/* Opcode: PutStrKey P1 * *
**
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_CSCHANGE ) db->csChange++;
if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
pC->nextRowidValid = 0;
}
** a record from within an Next loop.
**
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
-** incremented (otherwise not). If OPFLAG_CSCHANGE flag is set,
-** then the current statement change count is incremented (otherwise not).
+** incremented (otherwise not).
**
** If P1 is a pseudo-table, then this instruction is a no-op.
*/
pC->nextRowidValid = 0;
pC->cacheValid = 0;
}
- if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++;
- if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++;
+ if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
}
-/* Opcode: SetCounts * * *
+/* Opcode: ResetCount P1 * *
**
-** Called at end of statement. Updates lsChange (last statement change count)
-** and resets csChange (current statement change count) to 0.
+** This opcode resets the VMs internal change counter to 0. If P1 is true,
+** 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: {
- db->lsChange=db->csChange;
- db->csChange=0;
+case OP_ResetCount: {
+ if( pOp->p1 ){
+ sqlite3VdbeSetChanges(p->db, p->nChange);
+ }
+ p->nChange = 0;
break;
}
case OP_ListPush: {
p->keylistStackDepth++;
assert(p->keylistStackDepth > 0);
+
+ /* FIX ME: This should be allocated at compile time. */
p->keylistStack = sqliteRealloc(p->keylistStack,
sizeof(Keylist *) * p->keylistStackDepth);
if( p->keylistStack==0 ) goto no_mem;
+
p->keylistStack[p->keylistStackDepth - 1] = p->pList;
p->pList = 0;
break;
*/
case OP_ContextPush: {
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,
sizeof(Context) * p->contextStackDepth);
if( p->contextStack==0 ) goto no_mem;
+
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].csChange = p->db->csChange;
+#endif
break;
}
assert(p->contextStackDepth > 0);
p->contextStackDepth--;
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->csChange = p->contextStack[p->contextStackDepth].csChange;
+#endif
if( p->contextStackDepth == 0 ){
sqliteFree(p->contextStack);
p->contextStack = 0;
** or VDBE. The VDBE implements an abstract machine that runs a
** 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_
#define _SQLITE_VDBE_H_
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
+void sqlite3VdbeCountChanges(Vdbe*);
#ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...);
*/
typedef struct Context Context;
struct Context {
- int lastRowid; /* Last insert rowid (from db->lastRowid) */
- int lsChange; /* Last statement change count (from db->lsChange) */
- int csChange; /* Current statement change count (from db->csChange) */
+ int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
+ int nChange; /* Statement changes (Vdbe.nChanges) */
};
/*
u8 resOnStack; /* True if there are result values on the stack */
u8 explain; /* True if EXPLAIN present on SQL command */
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 */
};
/*
p->popStack = 0;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
+ p->nChange = 0;
#ifdef VDBE_PROFILE
{
int i;
}
}
+ /* 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 ){
sqlite3RollbackInternalChanges(db);
sqliteFree(pOp->p3);
}
if( pOp->p3type==P3_VDBEFUNC ){
- int j;
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
sqlite3VdbeDeleteAuxData(pVdbeFunc, -1);
sqliteFree(pVdbeFunc);
sqlite3VdbeMemRelease(&m);
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;
+}
+
+
+
# This file implements regression tests for SQLite library. The
# 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]
# 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?
-do_test capi2-3.10b {sqlite3_changes $DB} {1}
+do_test capi2-3.10b {db changes} {0}
do_test capi2-3.11 {
sqlite3_finalize $VM
} {SQLITE_OK}
-do_test capi2-3.11b {sqlite3_changes $DB} {1}
+do_test capi2-3.11b {db changes} {1}
do_test capi2-3.12 {
sqlite3_finalize $VM
} {SQLITE_MISUSE}
[get_row_values $VM] \
[get_column_names $VM]
} {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 {
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
} {SQLITE_CONSTRAINT {column a is not unique}}
SELECT * FROM t1;
}
} {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 {
sqlite3_changes $DB
-} {0}
+} {4}
+do_test capi2-7.11a {
+ execsql {SELECT count(*) FROM t1}
+} {4}
+
do_test capi2-7.12 {
set x [stepsql $DB {EXPLAIN SELECT * FROM t1}]
lindex $x 0
# This file implements tests for the conflict resolution extension
# 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]
source $testdir/tester.tcl
SELECT count(*) FROM t1;
}
} {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 {
db changes
-} {0}
+} {50}
# Make sure the row count is right for rows that are ignored on
# an insert.
# focus of this file is testing the INSERT statement that takes is
# 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]
source $testdir/tester.tcl
}
} {1 2}
do_test insert2-3.2 {
+ set x [db total_changes]
execsql {
BEGIN;
INSERT INTO t4 VALUES(2,4);
INSERT INTO t4 VALUES(10,20);
COMMIT;
}
- db changes
+ expr [db total_changes] - $x
} {9}
do_test insert2-3.2.1 {
execsql {
#
#***********************************************************************
#
-# Tests to make sure that value returned by last_statement_change_count()
-# (LSCC) is updated properly, especially inside triggers
+# Tests to make sure that values returned by changes() and total_changes()
+# are updated properly, especially inside triggers
#
-# Note 1: LSCC remains constant within a statement and only updates once
-# the statement is finished (triggers count as part of statement)
-# Note 2: LSCC is changed within the context of a trigger
-# much like last_insert_rowid() (see lastinsert.test),
-# but is restored once the trigger exits
-# Note 3: LSCC is not changed by a change to a view (since everything
-# is done within instead of trigger context)
+# Note 1: changes() remains constant within a statement and only updates
+# once the statement is finished (triggers count as part of
+# statement).
+# Note 2: changes() is changed within the context of a trigger much like
+# last_insert_rowid() (see lastinsert.test), but is restored once
+# the trigger exits.
+# 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]
# ----------------------------------------------------------------------------
# 1.x - basic tests (no triggers)
-# LSCC set properly after insert
+# changes() set properly after insert
do_test laststmtchanges-1.1 {
catchsql {
create table t0 (x);
insert into t0 values (1);
insert into t0 values (1);
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 {
catchsql {
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 {
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;
}
} {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 {
catchsql {
update t0 set x=77 where x=88;
- select last_statement_change_count();
+ select changes();
}
} {0 0}
-# LSCC set properly after delete from table
+# changes() set properly after delete from table
do_test laststmtchanges-1.5 {
catchsql {
delete from t0 where x=2;
- select last_statement_change_count();
+ select changes();
}
} {0 3}
# ----------------------------------------------------------------------------
# 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 {
+ set ::tc [db total_changes]
catchsql {
create table t1 (k integer primary key);
create table t2 (k integer primary key, v1, v2);
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 t2 set v2=last_statement_change_count();
+ update t2 set v2=changes();
end;
insert into t1 values (77);
- select last_statement_change_count();
+ select changes();
}
} {0 1}
-# LSCC unchanged upon entry into after insert trigger
+# changes() unchanged upon entry into after insert trigger
do_test laststmtchanges-2.2 {
catchsql {
select v1 from t2;
}
} {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 {
catchsql {
select v2 from t2;
}
} {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
-# 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 {
catchsql {
drop trigger r1;
delete from t2; delete from t2;
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;
- update t2 set v2=last_statement_change_count();
+ update t2 set v2=changes();
end;
update t1 set k=k;
- select last_statement_change_count();
+ select changes();
}
} {0 1}
-# LSCC unchanged upon entry into after update trigger
+# changes() unchanged upon entry into after update trigger
do_test laststmtchanges-3.2 {
catchsql {
select v1 from t2;
}
} {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 {
catchsql {
select v2 from t2;
# ----------------------------------------------------------------------------
# 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 {
catchsql {
drop trigger r1;
delete from t2; delete from t2;
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);
- update t2 set v2=last_statement_change_count();
+ update t2 set v2=changes();
end;
delete from t1;
- select last_statement_change_count();
+ select changes();
}
} {0 1}
-# LSCC unchanged upon entry into before delete trigger
+# changes() unchanged upon entry into before delete trigger
do_test laststmtchanges-4.2 {
catchsql {
select v1 from t2;
}
} {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 {
catchsql {
select v2 from t2;
insert into t0 values (2);
insert into t0 values (1);
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;
- insert into n1 values (NULL, last_statement_change_count());
+ insert into n1 values (NULL, changes());
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;
insert into v2 values (100+NEW.k);
- insert into n1 values (NULL, last_statement_change_count());
+ insert into n1 values (NULL, changes());
end;
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 n2 values (NULL, last_statement_change_count());
+ insert into n2 values (NULL, changes());
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;
- insert into n2 values (NULL, last_statement_change_count());
+ insert into n2 values (NULL, changes());
end;
insert into t1 values (77);
- select last_statement_change_count();
+ select changes();
}
} {0 1}
do_test laststmtchanges-5.2 {
catchsql {
delete from t1 where k=88;
- select last_statement_change_count();
+ select changes();
}
} {0 0}
do_test laststmtchanges-5.3 {
catchsql {
insert into v1 values (5);
- select last_statement_change_count();
+ select changes();
}
} {0 0}
# 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.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]
source $testdir/tester.tcl
do_test tcl-1.2 {
set v [catch {db bogus} 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 {
execsql {CREATE TABLE t1(a int, b int)}
execsql {INSERT INTO t1 VALUES(10,20)}