mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Enhance the internal sqlite3VdbeAddOpList() interface to automatically update
jump destinations. Use this feature to simplify the AUTOINCREMENT code generator. FossilOrigin-Name: ae8b9d2edf1b5aef6108e729754911db7682b6a3
This commit is contained in:
73
src/insert.c
73
src/insert.c
@@ -254,7 +254,6 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
||||
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 */
|
||||
|
||||
/* This routine is never called during trigger-generation. It is
|
||||
@@ -264,33 +263,46 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
||||
|
||||
assert( v ); /* We failed long ago if this is not so */
|
||||
for(p = pParse->pAinc; p; p = p->pNext){
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList autoInc[] = {
|
||||
/* 0 */ {OP_Null, 0, 0, 0},
|
||||
/* 1 */ {OP_Rewind, 0, 9, 0},
|
||||
/* 2 */ {OP_Column, 0, 0, 0},
|
||||
/* 3 */ {OP_Ne, 0, 7, 0},
|
||||
/* 4 */ {OP_Rowid, 0, 0, 0},
|
||||
/* 5 */ {OP_Column, 0, 1, 0},
|
||||
/* 6 */ {OP_Goto, 0, 9, 0},
|
||||
/* 7 */ {OP_Next, 0, 2, 0},
|
||||
/* 8 */ {OP_Integer, 0, 0, 0},
|
||||
/* 9 */ {OP_Close, 0, 0, 0}
|
||||
};
|
||||
VdbeOp *aOp;
|
||||
pDb = &db->aDb[p->iDb];
|
||||
memId = p->regCtr;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
||||
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
|
||||
sqlite3VdbeGoto(v, addr+9);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
|
||||
sqlite3VdbeAddOp0(v, OP_Close);
|
||||
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
|
||||
if( aOp==0 ) break;
|
||||
aOp[0].p2 = memId;
|
||||
aOp[0].p3 = memId+1;
|
||||
aOp[2].p3 = memId;
|
||||
aOp[3].p1 = memId-1;
|
||||
aOp[3].p3 = memId;
|
||||
aOp[3].p5 = SQLITE_JUMPIFNULL;
|
||||
aOp[4].p2 = memId+1;
|
||||
aOp[5].p3 = memId;
|
||||
aOp[8].p2 = memId;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Update the maximum rowid for an autoincrement calculation.
|
||||
**
|
||||
** This routine should be called when the top of the stack holds a
|
||||
** This routine should be called when the regRowid register holds a
|
||||
** new rowid that is about to be inserted. If that new rowid is
|
||||
** larger than the maximum rowid in the memId memory cell, then the
|
||||
** memory cell is updated. The stack is unchanged.
|
||||
** memory cell is updated.
|
||||
*/
|
||||
static void autoIncStep(Parse *pParse, int memId, int regRowid){
|
||||
if( memId>0 ){
|
||||
@@ -305,31 +317,44 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
|
||||
** table (either directly or through triggers) needs to call this
|
||||
** routine just before the "exit" code.
|
||||
*/
|
||||
void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
|
||||
AutoincInfo *p;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( v );
|
||||
for(p = pParse->pAinc; p; p = p->pNext){
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList autoIncEnd[] = {
|
||||
/* 0 */ {OP_NotNull, 0, 2, 0},
|
||||
/* 1 */ {OP_NewRowid, 0, 0, 0},
|
||||
/* 2 */ {OP_MakeRecord, 0, 2, 0},
|
||||
/* 3 */ {OP_Insert, 0, 0, 0},
|
||||
/* 4 */ {OP_Close, 0, 0, 0}
|
||||
};
|
||||
VdbeOp *aOp;
|
||||
Db *pDb = &db->aDb[p->iDb];
|
||||
int addr1;
|
||||
int iRec;
|
||||
int memId = p->regCtr;
|
||||
|
||||
iRec = sqlite3GetTempReg(pParse);
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
||||
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
||||
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp0(v, OP_Close);
|
||||
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
|
||||
if( aOp==0 ) break;
|
||||
aOp[0].p1 = memId+1;
|
||||
aOp[1].p2 = memId+1;
|
||||
aOp[2].p1 = memId-1;
|
||||
aOp[2].p3 = iRec;
|
||||
aOp[3].p2 = iRec;
|
||||
aOp[3].p3 = memId+1;
|
||||
aOp[3].p5 = OPFLAG_APPEND;
|
||||
sqlite3ReleaseTempReg(pParse, iRec);
|
||||
}
|
||||
}
|
||||
void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
if( pParse->pAinc ) autoIncrementEnd(pParse);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
|
||||
|
||||
Reference in New Issue
Block a user