]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance autoincrement so that it works with triggers that also do
authordrh <drh@noemail.net>
Tue, 23 Jun 2009 20:28:53 +0000 (20:28 +0000)
committerdrh <drh@noemail.net>
Tue, 23 Jun 2009 20:28:53 +0000 (20:28 +0000)
autoincrement inserts, even multiple inserts into the same table.
Ticket #3928 (CVS 6807)

FossilOrigin-Name: 1330993de8eae7baeec24100216158063c9bdc19

manifest
manifest.uuid
src/build.c
src/delete.c
src/insert.c
src/sqliteInt.h
src/tokenize.c
src/update.c
test/autoinc.test

index e6daa65ad09f3edd48ce281c5bdb8933cd1a0df4..fe94c740c967c2e4bc776bd7f34f536fa9ff95d5 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sa\scondition\sfrom\sbalance_nonroot()\sthat\sis\salways\strue.\s(CVS\s6806)
-D 2009-06-23T16:40:18
+C Enhance\sautoincrement\sso\sthat\sit\sworks\swith\striggers\sthat\salso\sdo\r\nautoincrement\sinserts,\seven\smultiple\sinserts\sinto\sthe\ssame\stable.\r\nTicket\s#3928\s(CVS\s6807)
+D 2009-06-23T20:28:54
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 8b8fb7823264331210cddf103831816c286ba446
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -109,11 +109,11 @@ F src/btmutex.c 9b899c0d8df3bd68f527b0afe03088321b696d3c
 F src/btree.c 807e32c181e681ffd3468d114b5cb11c63984842
 F src/btree.h f70b694e8c163227369a66863b01fbff9009f323
 F src/btreeInt.h 7267e965e34314aa2bddbdde268b31e1034eda9c
-F src/build.c e98868af6a04c8d7191c39fd05c69da34a8d9c68
+F src/build.c d930b3899aea564f01a581e0e9429d92fb5f98f0
 F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf
 F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
 F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
-F src/delete.c cb791855c7948cecc96def9d97989879ca26f257
+F src/delete.c fb05e577ab273cc8a63b44809aa5078f72f475c1
 F src/expr.c de80e2d6c2adc453e06f070837ca5b87d4373730
 F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
 F src/func.c 9856373f5315f6b8690d7f07f7191aa9f279ca87
@@ -121,7 +121,7 @@ F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
 F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
 F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
-F src/insert.c 69ef88ce30d1f65315b57aba63b2d4e9bdca1090
+F src/insert.c 94e51344e01aea6be43e95cd24e8baa014d8c3d6
 F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
 F src/legacy.c 9a56cf126ceee332b56061bf16bd0fb4ff9e26c0
 F src/loadext.c 0e88a335665db0b2fb4cece3e49dcb65d832635a
@@ -162,7 +162,7 @@ F src/select.c 71748b8e244112cf73df9446c4246c192276c30d
 F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
 F src/sqlite.h.in ccc67f14d5661240d05eadb8ab308aa637b0630c
 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 9fd22fed12cbb0eccfe14108796ae05fa473786e
+F src/sqliteInt.h 2dc684cd94560b0de876098e49d8a91996291a76
 F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
 F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
@@ -197,9 +197,9 @@ F src/test_server.c f0a403b5f699c09bd2b1236b6f69830fd6221f6b
 F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
 F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
 F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
-F src/tokenize.c 3743be86c3e73081b5b162adc00e2492a94a3a99
+F src/tokenize.c eadd396fa81e8031d4b4a65eefd661e9c675167f
 F src/trigger.c c07c5157c58fcdb704f65d5f5e4775276e45bb8b
-F src/update.c 6ae6c26adff8dc34532d578f66e6cfde04b5d177
+F src/update.c b58db45e40f11082281d6f94137cd3b5657771d9
 F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
 F src/util.c a7e981e032c3c9c0887d50d7e658a33cb355b43d
 F src/vacuum.c 0e14f371ea3326c6b8cfba257286d798cd20db59
@@ -233,7 +233,7 @@ F test/attachmalloc.test cf8cf17d183de357b1147a9baacbdfc85b940b61
 F test/auth.test b66c571142873cfbf9a141b807f78b93f5d11374
 F test/auth2.test ee3ba272e2b975e913afc9b041ee75706e190005
 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
-F test/autoinc.test ab549b48b389cabd92967b86c379ec8b31fa6c16
+F test/autoinc.test 71bc5183c93ed5e2b8b3a71c218d777b55e4fffc
 F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
 F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
 F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
@@ -737,7 +737,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
-P da9893e23caf89090c8b6563cb5f88d7dbf7c260
-R 5253d044c7ec7582bf7c9fd280850376
-U danielk1977
-Z 1a116d3d2ab282f253ce6bf047ecc40c
+P c5dc80e6bdd18a5ada728c8d5c9403ac233f1c9a
+R 8916621e1801546a3d0feafac918adbe
+U drh
+Z cb8dc29a045e11a78c5fa19e64b5f95b
index ee7d59a3cc902910b5a5fefa763131d34f90c809..09a7f53599922e417ee22cfaf721d0707c986b1e 100644 (file)
@@ -1 +1 @@
-c5dc80e6bdd18a5ada728c8d5c9403ac233f1c9a
\ No newline at end of file
+1330993de8eae7baeec24100216158063c9bdc19
\ No newline at end of file
index 53d03b7437272148dc244119cacf19744c03166c..850ec7fa2337e025484b4782ad1ae110ccd6061f 100644 (file)
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.552 2009/06/18 17:22:39 drh Exp $
+** $Id: build.c,v 1.553 2009/06/23 20:28:54 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -174,6 +174,12 @@ void sqlite3FinishCoding(Parse *pParse){
       ** shared-cache feature is enabled.
       */
       codeTableLocks(pParse);
+
+      /* Initialize any AUTOINCREMENT data structures required.
+      */
+      sqlite3AutoincrementBegin(pParse);
+
+      /* Finally, jump back to the beginning of the executable code. */
       sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
     }
   }
index 95ef3cef7439794d7d6314277f4f80f4f5162071..cbd8b375e73095ec6582ce2b9a10667f73b4162b 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.203 2009/05/28 01:00:55 drh Exp $
+** $Id: delete.c,v 1.204 2009/06/23 20:28:54 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -475,6 +475,14 @@ void sqlite3DeleteFrom(
     }
   }
 
+  /* Update the sqlite_sequence table by storing the content of the
+  ** maximum rowid counter values recorded while inserting into
+  ** autoincrement tables.
+  */
+  if( pParse->nested==0 && pParse->trigStack==0 ){
+    sqlite3AutoincrementEnd(pParse);
+  }
+
   /*
   ** Return the number of rows that were deleted. If this routine is 
   ** generating code because of a call to sqlite3NestedParse(), do not
index 27549f0018d29397685c1f9a9359e4b7a5f2777b..f6d8b1c3905eab2225d81c5d804a0354599b750f 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.268 2009/05/29 19:00:13 drh Exp $
+** $Id: insert.c,v 1.269 2009/06/23 20:28:54 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -162,22 +162,24 @@ static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
 
 #ifndef SQLITE_OMIT_AUTOINCREMENT
 /*
-** Write out code to initialize the autoincrement logic.  This code
-** looks up the current autoincrement value in the sqlite_sequence
-** table and stores that value in a register.  Code generated by
-** autoIncStep() will keep that register holding the largest
-** rowid value.  Code generated by autoIncEnd() will write the new
-** largest value of the counter back into the sqlite_sequence table.
+** Locate or create an AutoincInfo structure associated with table pTab
+** which is in database iDb.  Return the register number for the register
+** that holds the maximum rowid.
 **
-** This routine returns the index of the mem[] cell that contains
-** the maximum rowid counter.
+** There is at most one AutoincInfo structure per table even if the
+** same table is autoincremented multiple times due to inserts within
+** triggers.  A new AutoincInfo structure is created if this is the
+** first use of table pTab.  On 2nd and subsequent uses, the original
+** AutoincInfo structure is used.
 **
-** Three consecutive registers are allocated by this routine.  The
-** first two hold the name of the target table and the maximum rowid 
-** inserted into the target table, respectively.
-** The third holds the rowid in sqlite_sequence where we will
-** write back the revised maximum rowid.  This routine returns the
-** index of the second of these three registers.
+** Three memory locations are allocated:
+**
+**   (1)  Register to hold the name of the pTab table.
+**   (2)  Register to hold the maximum ROWID of pTab.
+**   (3)  Register to hold the rowid in sqlite_sequence of pTab
+**
+** The 2nd register is the one that is returned.  That is all the
+** insert routine needs to know about.
 */
 static int autoIncBegin(
   Parse *pParse,      /* Parsing context */
@@ -186,29 +188,56 @@ static int autoIncBegin(
 ){
   int memId = 0;      /* Register holding maximum rowid */
   if( pTab->tabFlags & TF_Autoincrement ){
-    Vdbe *v = pParse->pVdbe;
-    Db *pDb = &pParse->db->aDb[iDb];
-    int iCur = pParse->nTab++;
-    int addr;               /* Address of the top of the loop */
-    assert( v );
-    pParse->nMem++;         /* Holds name of table */
-    memId = ++pParse->nMem;
-    pParse->nMem++;
-    sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
+    AutoincInfo *pInfo;
+
+    pInfo = pParse->pAinc;
+    while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
+    if( pInfo==0 ){
+      pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
+      if( pInfo==0 ) return 0;
+      pInfo->pNext = pParse->pAinc;
+      pParse->pAinc = pInfo;
+      pInfo->pTab = pTab;
+      pInfo->iDb = iDb;
+      pParse->nMem++;                  /* Register to hold name of table */
+      pInfo->regCtr = ++pParse->nMem;  /* Max rowid register */
+      pParse->nMem++;                  /* Rowid in sqlite_sequence */
+    }
+    memId = pInfo->regCtr;
+  }
+  return memId;
+}
+
+/*
+** This routine generates code that will initialize all of the
+** register used by the autoincrement tracker.  
+*/
+void sqlite3AutoincrementBegin(Parse *pParse){
+  AutoincInfo *p;            /* Information about an AUTOINCREMENT */
+  sqlite3 *db = pParse->db;  /* The database connection */
+  Db *pDb;                   /* Database only autoinc table */
+  int memId;                 /* Register holding max rowid */
+  int addr;                  /* A VDBE address */
+  Vdbe *v = pParse->pVdbe;   /* VDBE under construction */
+
+  assert( v );   /* We failed long ago if this is not so */
+  for(p = pParse->pAinc; p; p = p->pNext){
+    pDb = &db->aDb[p->iDb];
+    memId = p->regCtr;
+    sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
     addr = sqlite3VdbeCurrentAddr(v);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0);
-    sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+9);
-    sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, memId);
+    sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
+    sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
+    sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
     sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId);
     sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
-    sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1);
-    sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId);
+    sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
+    sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
     sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
-    sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2);
+    sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2);
     sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
-    sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
+    sqlite3VdbeAddOp0(v, OP_Close);
   }
-  return memId;
 }
 
 /*
@@ -226,32 +255,43 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
 }
 
 /*
-** After doing one or more inserts, the maximum rowid is stored
-** in reg[memId].  Generate code to write this value back into the
-** the sqlite_sequence table.
+** This routine generates the code needed to write autoincrement
+** maximum rowid values back into the sqlite_sequence register.
+** Every statement that might do an INSERT into an autoincrement
+** table (either directly or through triggers) needs to call this
+** routine just before the "exit" code.
 */
-static void autoIncEnd(
-  Parse *pParse,     /* The parsing context */
-  int iDb,           /* Index of the database holding pTab */
-  Table *pTab,       /* Table we are inserting into */
-  int memId          /* Memory cell holding the maximum rowid */
-){
-  if( pTab->tabFlags & TF_Autoincrement ){
-    int iCur = pParse->nTab++;
-    Vdbe *v = pParse->pVdbe;
-    Db *pDb = &pParse->db->aDb[iDb];
-    int j1;
-    int iRec = ++pParse->nMem;    /* Memory cell used for record */
-
-    assert( v );
-    sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
+void sqlite3AutoincrementEnd(Parse *pParse){
+  AutoincInfo *p;
+  Vdbe *v = pParse->pVdbe;
+  sqlite3 *db = pParse->db;
+
+  assert( v );
+  for(p = pParse->pAinc; p; p = p->pNext){
+    Db *pDb = &db->aDb[p->iDb];
+    int j1, j2, j3, j4, j5;
+    int iRec;
+    int memId = p->regCtr;
+
+    iRec = sqlite3GetTempReg(pParse);
+    sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
     j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1);
-    sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1);
+    j2 = sqlite3VdbeAddOp0(v, OP_Rewind);
+    j3 = sqlite3VdbeAddOp3(v, OP_Column, 0, 0, iRec);
+    j4 = sqlite3VdbeAddOp3(v, OP_Eq, memId-1, 0, iRec);
+    sqlite3VdbeAddOp2(v, OP_Next, 0, j3);
+    sqlite3VdbeJumpHere(v, j2);
+    sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
+    j5 = sqlite3VdbeAddOp0(v, OP_Goto);
+    sqlite3VdbeJumpHere(v, j4);
+    sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
     sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeJumpHere(v, j5);
     sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
-    sqlite3VdbeAddOp3(v, OP_Insert, iCur, iRec, memId+1);
+    sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
-    sqlite3VdbeAddOp1(v, OP_Close, iCur);
+    sqlite3VdbeAddOp0(v, OP_Close);
+    sqlite3ReleaseTempReg(pParse, iRec);
   }
 }
 #else
@@ -261,7 +301,6 @@ static void autoIncEnd(
 */
 # define autoIncBegin(A,B,C) (0)
 # define autoIncStep(A,B,C)
-# define autoIncEnd(A,B,C,D)
 #endif /* SQLITE_OMIT_AUTOINCREMENT */
 
 
@@ -507,7 +546,7 @@ void sqlite3Insert(
   if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
     assert( !pTrigger );
     assert( pList==0 );
-    goto insert_cleanup;
+    goto insert_end;
   }
 #endif /* SQLITE_OMIT_XFER_OPT */
 
@@ -989,11 +1028,14 @@ void sqlite3Insert(
     }
   }
 
+insert_end:
   /* Update the sqlite_sequence table by storing the content of the
-  ** counter value in memory regAutoinc back into the sqlite_sequence
-  ** table.
+  ** maximum rowid counter values recorded while inserting into
+  ** autoincrement tables.
   */
-  autoIncEnd(pParse, iDb, pTab, regAutoinc);
+  if( pParse->nested==0 && pParse->trigStack==0 ){
+    sqlite3AutoincrementEnd(pParse);
+  }
 
   /*
   ** Return the number of rows inserted. If this routine is 
@@ -1716,7 +1758,6 @@ static int xferOptimization(
   sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
   sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
   sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
-  autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
   for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
     for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
       if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
index b0d047b715576bc53e02b632188b33379ca0976f..81c8e463091e299ac9d9951e58e0e8812dd6f9c0 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.886 2009/06/19 14:06:03 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.887 2009/06/23 20:28:54 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -581,6 +581,7 @@ struct BusyHandler {
 */
 typedef struct AggInfo AggInfo;
 typedef struct AuthContext AuthContext;
+typedef struct AutoincInfo AutoincInfo;
 typedef struct Bitvec Bitvec;
 typedef struct RowSet RowSet;
 typedef struct CollSeq CollSeq;
@@ -1926,6 +1927,22 @@ struct SelectDest {
   int nMem;         /* Number of registers allocated */
 };
 
+/*
+** During code generation of statements that do inserts into AUTOINCREMENT 
+** tables, the following information is attached to the Table.u.autoInc.p
+** pointer of each autoincrement table to record some side information that
+** the code generator needs.  We have to keep per-table autoincrement
+** information in case inserts are down within triggers.  Triggers do not
+** normally coordinate their activities, but we do need to coordinate the
+** loading and saving of autoincrement information.
+*/
+struct AutoincInfo {
+  AutoincInfo *pNext;   /* Next info block in a list of them all */
+  Table *pTab;          /* Table this info block refers to */
+  int iDb;              /* Index in sqlite3.aDb[] of database holding pTab */
+  int regCtr;           /* Memory register holding the rowid counter */
+};
+
 /*
 ** Size of the column cache
 */
@@ -1992,6 +2009,7 @@ struct Parse {
 #endif
   int regRowid;        /* Register holding rowid of CREATE TABLE entry */
   int regRoot;         /* Register holding root page number for new objects */
+  AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
 
   /* Above is constant between recursions.  Below is reset before and after
   ** each recursion */
@@ -2482,6 +2500,13 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
 
 void sqlite3DropTable(Parse*, SrcList*, int, int);
 void sqlite3DeleteTable(Table*);
+#ifndef SQLITE_OMIT_AUTOINCREMENT
+  void sqlite3AutoincrementBegin(Parse *pParse);
+  void sqlite3AutoincrementEnd(Parse *pParse);
+#else
+# define sqlite3AutoincrementBegin(X)
+# define sqlite3AutoincrementEnd(X)
+#endif
 void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
 void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*);
 IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
index 6761f8c3c29060bd464481f6d70bd40e9d9135dc..3fdb38edebe74ec45be931cfae2530a7e57666ec 100644 (file)
@@ -15,7 +15,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.161 2009/06/17 01:17:13 drh Exp $
+** $Id: tokenize.c,v 1.162 2009/06/23 20:28:54 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdlib.h>
@@ -518,6 +518,11 @@ abort_parse:
   sqlite3DeleteTrigger(db, pParse->pNewTrigger);
   sqlite3DbFree(db, pParse->apVarExpr);
   sqlite3DbFree(db, pParse->aAlias);
+  while( pParse->pAinc ){
+    AutoincInfo *p = pParse->pAinc;
+    pParse->pAinc = p->pNext;
+    sqlite3DbFree(db, p);
+  }
   while( pParse->pZombieTab ){
     Table *p = pParse->pZombieTab;
     pParse->pZombieTab = p->pNextZombie;
index 6eb92fb615c01a2ae3187f353e93ebf4107bb50c..12348c91a7c9410c2aad3cd54a77a82a70a75fd2 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.202 2009/05/28 01:00:55 drh Exp $
+** $Id: update.c,v 1.203 2009/06/23 20:28:54 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -564,6 +564,14 @@ void sqlite3Update(
     sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0);
   }
 
+  /* Update the sqlite_sequence table by storing the content of the
+  ** maximum rowid counter values recorded while inserting into
+  ** autoincrement tables.
+  */
+  if( pParse->nested==0 && pParse->trigStack==0 ){
+    sqlite3AutoincrementEnd(pParse);
+  }
+
   /*
   ** Return the number of rows that were changed. If this routine is 
   ** generating code because of a call to sqlite3NestedParse(), do not
index c49fb61ebfd3686e8ed09f69cb37ab3f8b8d1463..9080a3997d1e0c43556017434169a0d7946f3b45 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is testing the AUTOINCREMENT features.
 #
-# $Id: autoinc.test,v 1.13 2008/08/11 18:44:58 drh Exp $
+# $Id: autoinc.test,v 1.14 2009/06/23 20:28:54 drh Exp $
 #
 
 set testdir [file dirname $argv0]
@@ -556,5 +556,82 @@ do_test autoinc-9.1 {
   }
 } {t3 0}
 
+# Ticket #3928.  Make sure that triggers to not make extra slots in
+# the SQLITE_SEQUENCE table.
+#
+do_test autoinc-3928.1 {
+  db eval {
+    CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
+    CREATE TRIGGER t3928r1 BEFORE INSERT ON t3928 BEGIN
+      INSERT INTO t3928(b) VALUES('before1');
+      INSERT INTO t3928(b) VALUES('before2');
+    END;
+    CREATE TRIGGER t3928r2 AFTER INSERT ON t3928 BEGIN
+      INSERT INTO t3928(b) VALUES('after1');
+      INSERT INTO t3928(b) VALUES('after2');
+    END;
+    INSERT INTO t3928(b) VALUES('test');
+    SELECT * FROM t3928 ORDER BY a;
+  }
+} {1 before1 2 after1 3 after2 4 before2 5 after1 6 after2 7 test 8 before1 9 before2 10 after1 11 before1 12 before2 13 after2}
+do_test autoinc-3928.2 {
+  db eval {
+    SELECT * FROM sqlite_sequence WHERE name='t3928'
+  }
+} {t3928 13}
+
+do_test autoinc-3928.3 {
+  db eval {
+    DROP TRIGGER t3928r1;
+    DROP TRIGGER t3928r2;
+    CREATE TRIGGER t3928r3 BEFORE UPDATE ON t3928 
+      WHEN typeof(new.b)=='integer' BEGIN
+         INSERT INTO t3928(b) VALUES('before-int-' || new.b);
+    END;
+    CREATE TRIGGER t3928r4 AFTER UPDATE ON t3928 
+      WHEN typeof(new.b)=='integer' BEGIN
+         INSERT INTO t3928(b) VALUES('after-int-' || new.b);
+    END;
+    DELETE FROM t3928 WHERE a!=1;
+    UPDATE t3928 SET b=456 WHERE a=1;
+    SELECT * FROM t3928 ORDER BY a;
+  }
+} {1 456 14 before-int-456 15 after-int-456}
+do_test autoinc-3928.4 {
+  db eval {
+    SELECT * FROM sqlite_sequence WHERE name='t3928'
+  }
+} {t3928 15}
+
+do_test autoinc-3928.5 {
+  db eval {
+    CREATE TABLE t3928b(x);
+    INSERT INTO t3928b VALUES(100);
+    INSERT INTO t3928b VALUES(200);
+    INSERT INTO t3928b VALUES(300);
+    DELETE FROM t3928;
+    CREATE TABLE t3928c(y INTEGER PRIMARY KEY AUTOINCREMENT, z);
+    CREATE TRIGGER t3928br1 BEFORE DELETE ON t3928b BEGIN
+      INSERT INTO t3928(b) VALUES('before-del-'||old.x);
+      INSERT INTO t3928c(z) VALUES('before-del-'||old.x);
+    END;
+    CREATE TRIGGER t3928br2 AFTER DELETE ON t3928b BEGIN
+      INSERT INTO t3928(b) VALUES('after-del-'||old.x);
+      INSERT INTO t3928c(z) VALUES('after-del-'||old.x);
+    END;
+    DELETE FROM t3928b;
+    SELECT * FROM t3928 ORDER BY a;
+  }
+} {16 before-del-100 17 after-del-100 18 before-del-200 19 after-del-200 20 before-del-300 21 after-del-300}
+do_test autoinc-3928.6 {
+  db eval {
+    SELECT * FROM t3928c ORDER BY y;
+  }
+} {1 before-del-100 2 after-del-100 3 before-del-200 4 after-del-200 5 before-del-300 6 after-del-300}
+do_test autoinc-3928.7 {
+  db eval {
+    SELECT * FROM sqlite_sequence WHERE name LIKE 't3928%' ORDER BY name;
+  }
+} {t3928 21 t3928c 6}
 
 finish_test