Enhance autoincrement so that it works with triggers that also do

autoincrement inserts, even multiple inserts into the same table.
Ticket #3928 (CVS 6807)

FossilOrigin-Name: 1330993de8eae7baeec24100216158063c9bdc19
This commit is contained in:
drh 2009-06-23 20:28:53 +00:00
parent 1c3d2bf9cf
commit 0b9f50d8aa
9 changed files with 252 additions and 82 deletions

View File

@ -1,5 +1,5 @@
C Remove\sa\scondition\sfrom\sbalance_nonroot()\sthat\sis\salways\strue.\s(CVS\s6806) 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-23T16:40:18 D 2009-06-23T20:28:54
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 8b8fb7823264331210cddf103831816c286ba446 F Makefile.in 8b8fb7823264331210cddf103831816c286ba446
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -109,11 +109,11 @@ F src/btmutex.c 9b899c0d8df3bd68f527b0afe03088321b696d3c
F src/btree.c 807e32c181e681ffd3468d114b5cb11c63984842 F src/btree.c 807e32c181e681ffd3468d114b5cb11c63984842
F src/btree.h f70b694e8c163227369a66863b01fbff9009f323 F src/btree.h f70b694e8c163227369a66863b01fbff9009f323
F src/btreeInt.h 7267e965e34314aa2bddbdde268b31e1034eda9c F src/btreeInt.h 7267e965e34314aa2bddbdde268b31e1034eda9c
F src/build.c e98868af6a04c8d7191c39fd05c69da34a8d9c68 F src/build.c d930b3899aea564f01a581e0e9429d92fb5f98f0
F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0 F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3 F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
F src/delete.c cb791855c7948cecc96def9d97989879ca26f257 F src/delete.c fb05e577ab273cc8a63b44809aa5078f72f475c1
F src/expr.c de80e2d6c2adc453e06f070837ca5b87d4373730 F src/expr.c de80e2d6c2adc453e06f070837ca5b87d4373730
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
F src/func.c 9856373f5315f6b8690d7f07f7191aa9f279ca87 F src/func.c 9856373f5315f6b8690d7f07f7191aa9f279ca87
@ -121,7 +121,7 @@ F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1 F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
F src/insert.c 69ef88ce30d1f65315b57aba63b2d4e9bdca1090 F src/insert.c 94e51344e01aea6be43e95cd24e8baa014d8c3d6
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0 F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
F src/legacy.c 9a56cf126ceee332b56061bf16bd0fb4ff9e26c0 F src/legacy.c 9a56cf126ceee332b56061bf16bd0fb4ff9e26c0
F src/loadext.c 0e88a335665db0b2fb4cece3e49dcb65d832635a F src/loadext.c 0e88a335665db0b2fb4cece3e49dcb65d832635a
@ -162,7 +162,7 @@ F src/select.c 71748b8e244112cf73df9446c4246c192276c30d
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
F src/sqlite.h.in ccc67f14d5661240d05eadb8ab308aa637b0630c F src/sqlite.h.in ccc67f14d5661240d05eadb8ab308aa637b0630c
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h 9fd22fed12cbb0eccfe14108796ae05fa473786e F src/sqliteInt.h 2dc684cd94560b0de876098e49d8a91996291a76
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
@ -197,9 +197,9 @@ F src/test_server.c f0a403b5f699c09bd2b1236b6f69830fd6221f6b
F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4 F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241 F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
F src/tokenize.c 3743be86c3e73081b5b162adc00e2492a94a3a99 F src/tokenize.c eadd396fa81e8031d4b4a65eefd661e9c675167f
F src/trigger.c c07c5157c58fcdb704f65d5f5e4775276e45bb8b F src/trigger.c c07c5157c58fcdb704f65d5f5e4775276e45bb8b
F src/update.c 6ae6c26adff8dc34532d578f66e6cfde04b5d177 F src/update.c b58db45e40f11082281d6f94137cd3b5657771d9
F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
F src/util.c a7e981e032c3c9c0887d50d7e658a33cb355b43d F src/util.c a7e981e032c3c9c0887d50d7e658a33cb355b43d
F src/vacuum.c 0e14f371ea3326c6b8cfba257286d798cd20db59 F src/vacuum.c 0e14f371ea3326c6b8cfba257286d798cd20db59
@ -233,7 +233,7 @@ F test/attachmalloc.test cf8cf17d183de357b1147a9baacbdfc85b940b61
F test/auth.test b66c571142873cfbf9a141b807f78b93f5d11374 F test/auth.test b66c571142873cfbf9a141b807f78b93f5d11374
F test/auth2.test ee3ba272e2b975e913afc9b041ee75706e190005 F test/auth2.test ee3ba272e2b975e913afc9b041ee75706e190005
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test ab549b48b389cabd92967b86c379ec8b31fa6c16 F test/autoinc.test 71bc5183c93ed5e2b8b3a71c218d777b55e4fffc
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6 F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650 F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
@ -737,7 +737,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746 F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
P da9893e23caf89090c8b6563cb5f88d7dbf7c260 P c5dc80e6bdd18a5ada728c8d5c9403ac233f1c9a
R 5253d044c7ec7582bf7c9fd280850376 R 8916621e1801546a3d0feafac918adbe
U danielk1977 U drh
Z 1a116d3d2ab282f253ce6bf047ecc40c Z cb8dc29a045e11a78c5fa19e64b5f95b

View File

@ -1 +1 @@
c5dc80e6bdd18a5ada728c8d5c9403ac233f1c9a 1330993de8eae7baeec24100216158063c9bdc19

View File

@ -22,7 +22,7 @@
** COMMIT ** COMMIT
** ROLLBACK ** 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" #include "sqliteInt.h"
@ -174,6 +174,12 @@ void sqlite3FinishCoding(Parse *pParse){
** shared-cache feature is enabled. ** shared-cache feature is enabled.
*/ */
codeTableLocks(pParse); 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); sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
} }
} }

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
** in order to generate code for DELETE FROM statements. ** 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" #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 ** Return the number of rows that were deleted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not ** generating code because of a call to sqlite3NestedParse(), do not

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.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" #include "sqliteInt.h"
@ -162,22 +162,24 @@ static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
#ifndef SQLITE_OMIT_AUTOINCREMENT #ifndef SQLITE_OMIT_AUTOINCREMENT
/* /*
** Write out code to initialize the autoincrement logic. This code ** Locate or create an AutoincInfo structure associated with table pTab
** looks up the current autoincrement value in the sqlite_sequence ** which is in database iDb. Return the register number for the register
** table and stores that value in a register. Code generated by ** that holds the maximum rowid.
** 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.
** **
** This routine returns the index of the mem[] cell that contains ** There is at most one AutoincInfo structure per table even if the
** the maximum rowid counter. ** 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 ** Three memory locations are allocated:
** first two hold the name of the target table and the maximum rowid **
** inserted into the target table, respectively. ** (1) Register to hold the name of the pTab table.
** The third holds the rowid in sqlite_sequence where we will ** (2) Register to hold the maximum ROWID of pTab.
** write back the revised maximum rowid. This routine returns the ** (3) Register to hold the rowid in sqlite_sequence of pTab
** index of the second of these three registers. **
** The 2nd register is the one that is returned. That is all the
** insert routine needs to know about.
*/ */
static int autoIncBegin( static int autoIncBegin(
Parse *pParse, /* Parsing context */ Parse *pParse, /* Parsing context */
@ -186,31 +188,58 @@ static int autoIncBegin(
){ ){
int memId = 0; /* Register holding maximum rowid */ int memId = 0; /* Register holding maximum rowid */
if( pTab->tabFlags & TF_Autoincrement ){ if( pTab->tabFlags & TF_Autoincrement ){
Vdbe *v = pParse->pVdbe; AutoincInfo *pInfo;
Db *pDb = &pParse->db->aDb[iDb];
int iCur = pParse->nTab++; pInfo = pParse->pAinc;
int addr; /* Address of the top of the loop */ while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
assert( v ); if( pInfo==0 ){
pParse->nMem++; /* Holds name of table */ pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
memId = ++pParse->nMem; if( pInfo==0 ) return 0;
pParse->nMem++; pInfo->pNext = pParse->pAinc;
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); pParse->pAinc = pInfo;
addr = sqlite3VdbeCurrentAddr(v); pInfo->pTab = pTab;
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0); pInfo->iDb = iDb;
sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+9); pParse->nMem++; /* Register to hold name of table */
sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, memId); pInfo->regCtr = ++pParse->nMem; /* Max rowid register */
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); pParse->nMem++; /* Rowid in sqlite_sequence */
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); }
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1); memId = pInfo->regCtr;
sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2);
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
} }
return memId; 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, 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, 0, memId+1);
sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2);
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
sqlite3VdbeAddOp0(v, OP_Close);
}
}
/* /*
** Update the maximum rowid for an autoincrement calculation. ** Update the maximum rowid for an autoincrement calculation.
** **
@ -226,32 +255,43 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
} }
/* /*
** After doing one or more inserts, the maximum rowid is stored ** This routine generates the code needed to write autoincrement
** in reg[memId]. Generate code to write this value back into the ** maximum rowid values back into the sqlite_sequence register.
** the sqlite_sequence table. ** 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( void sqlite3AutoincrementEnd(Parse *pParse){
Parse *pParse, /* The parsing context */ AutoincInfo *p;
int iDb, /* Index of the database holding pTab */ Vdbe *v = pParse->pVdbe;
Table *pTab, /* Table we are inserting into */ sqlite3 *db = pParse->db;
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 ); assert( v );
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); 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); 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, j1);
sqlite3VdbeJumpHere(v, j5);
sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec); 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); sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeAddOp1(v, OP_Close, iCur); sqlite3VdbeAddOp0(v, OP_Close);
sqlite3ReleaseTempReg(pParse, iRec);
} }
} }
#else #else
@ -261,7 +301,6 @@ static void autoIncEnd(
*/ */
# define autoIncBegin(A,B,C) (0) # define autoIncBegin(A,B,C) (0)
# define autoIncStep(A,B,C) # define autoIncStep(A,B,C)
# define autoIncEnd(A,B,C,D)
#endif /* SQLITE_OMIT_AUTOINCREMENT */ #endif /* SQLITE_OMIT_AUTOINCREMENT */
@ -507,7 +546,7 @@ void sqlite3Insert(
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
assert( !pTrigger ); assert( !pTrigger );
assert( pList==0 ); assert( pList==0 );
goto insert_cleanup; goto insert_end;
} }
#endif /* SQLITE_OMIT_XFER_OPT */ #endif /* SQLITE_OMIT_XFER_OPT */
@ -989,11 +1028,14 @@ void sqlite3Insert(
} }
} }
insert_end:
/* Update the sqlite_sequence table by storing the content of the /* Update the sqlite_sequence table by storing the content of the
** counter value in memory regAutoinc back into the sqlite_sequence ** maximum rowid counter values recorded while inserting into
** table. ** 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 ** 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); sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
sqlite3VdbeChangeP4(v, -1, pDest->zName, 0); sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){ for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@ -581,6 +581,7 @@ struct BusyHandler {
*/ */
typedef struct AggInfo AggInfo; typedef struct AggInfo AggInfo;
typedef struct AuthContext AuthContext; typedef struct AuthContext AuthContext;
typedef struct AutoincInfo AutoincInfo;
typedef struct Bitvec Bitvec; typedef struct Bitvec Bitvec;
typedef struct RowSet RowSet; typedef struct RowSet RowSet;
typedef struct CollSeq CollSeq; typedef struct CollSeq CollSeq;
@ -1926,6 +1927,22 @@ struct SelectDest {
int nMem; /* Number of registers allocated */ 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 ** Size of the column cache
*/ */
@ -1992,6 +2009,7 @@ struct Parse {
#endif #endif
int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */ 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 /* Above is constant between recursions. Below is reset before and after
** each recursion */ ** each recursion */
@ -2482,6 +2500,13 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
void sqlite3DropTable(Parse*, SrcList*, int, int); void sqlite3DropTable(Parse*, SrcList*, int, int);
void sqlite3DeleteTable(Table*); 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 sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*); void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*);
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** 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 "sqliteInt.h"
#include <stdlib.h> #include <stdlib.h>
@ -518,6 +518,11 @@ abort_parse:
sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->apVarExpr); sqlite3DbFree(db, pParse->apVarExpr);
sqlite3DbFree(db, pParse->aAlias); sqlite3DbFree(db, pParse->aAlias);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
pParse->pAinc = p->pNext;
sqlite3DbFree(db, p);
}
while( pParse->pZombieTab ){ while( pParse->pZombieTab ){
Table *p = pParse->pZombieTab; Table *p = pParse->pZombieTab;
pParse->pZombieTab = p->pNextZombie; pParse->pZombieTab = p->pNextZombie;

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.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" #include "sqliteInt.h"
@ -564,6 +564,14 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_Close, oldIdx, 0); 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 ** Return the number of rows that were changed. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not ** generating code because of a call to sqlite3NestedParse(), do not

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 is testing the AUTOINCREMENT features. # 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] set testdir [file dirname $argv0]
@ -556,5 +556,82 @@ do_test autoinc-9.1 {
} }
} {t3 0} } {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 finish_test