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:
parent
1c3d2bf9cf
commit
0b9f50d8aa
26
manifest
26
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
|
||||
|
@ -1 +1 @@
|
||||
c5dc80e6bdd18a5ada728c8d5c9403ac233f1c9a
|
||||
1330993de8eae7baeec24100216158063c9bdc19
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
10
src/delete.c
10
src/delete.c
@ -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
|
||||
|
165
src/insert.c
165
src/insert.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.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,31 +188,58 @@ 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);
|
||||
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);
|
||||
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_Goto, 0, addr+9);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
|
||||
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, 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.
|
||||
**
|
||||
@ -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 */
|
||||
void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
AutoincInfo *p;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( v );
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
||||
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;
|
||||
|
@ -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*);
|
||||
|
@ -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;
|
||||
|
10
src/update.c
10
src/update.c
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user