aboutsummaryrefslogtreecommitdiff
path: root/src/insert.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/insert.c')
-rw-r--r--src/insert.c159
1 files changed, 100 insertions, 59 deletions
diff --git a/src/insert.c b/src/insert.c
index 27549f001..f6d8b1c39 100644
--- a/src/insert.c
+++ b/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,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;