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:
drh 2016-02-03 01:55:44 +00:00
parent b06347a5dc
commit 1b32554b80
7 changed files with 80 additions and 52 deletions

View File

@ -1,5 +1,5 @@
C Add\stests\sto\srestore\sfull\scoverage\sof\sfts5\scode.
D 2016-02-02T21:19:21.156
C Enhance\sthe\sinternal\ssqlite3VdbeAddOpList()\sinterface\sto\sautomatically\supdate\njump\sdestinations.\s\sUse\sthis\sfeature\sto\ssimplify\sthe\sAUTOINCREMENT\scode\ngenerator.
D 2016-02-03T01:55:44.089
F Makefile.in 027c1603f255390c43a426671055a31c0a65fdb4
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 72b7858f02017611c3ac1ddc965251017fed0845
@ -309,7 +309,7 @@ F src/global.c bd5a0af3f30b0c01be6db756c626cd3c33a3d260
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 410f52b9ef4603dc0aebb169b7cb6b3c60eda07e
F src/insert.c 3e2462294fc8bc6e46f377ec824ff315e79fc36d
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/loadext.c 84996d7d70a605597d79c1f1d7b2012a5fd34f2b
@ -341,7 +341,7 @@ F src/parse.y 426a91fbbbf7cdde3fd4b8798de7317a8782bec5
F src/pcache.c 73895411fa6b7bd6f0091212feabbe833b358d23
F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051
F src/pragma.c 2ac26ac45eedbed3cc8a9a320ad6d2fc299e69a6
F src/pragma.c a973357ef2faded933725a6de2883133deb24029
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
F src/prepare.c db85f0451ba93ecb3c1e497c279abece5cb5aead
F src/printf.c 98a5cef7fc84577ab8a3098cfa48ecfa5a70b9f8
@ -353,7 +353,7 @@ F src/shell.c dcd7a83645ef2a58ee9c6d0ea4714d877d7835c4
F src/sqlite.h.in cf22ad1d52dca2c9862d63833e581028119aab7e
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
F src/sqliteInt.h 2f80b9b1506a8d602b2a99f3f0bfae22df3e7d70
F src/sqliteInt.h ed6f75088781af7cbd0a6653c2fe16340faa0dd4
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
@ -417,8 +417,8 @@ F src/vdbe.c a0a0ada4b51161d3950fe30fc696b6c8235a841f
F src/vdbe.h 7a733ea8aac1b77305a67698e784fa3484ee3337
F src/vdbeInt.h 4b69d5451bcadd473e745af53ef1e8abfdce0a79
F src/vdbeapi.c 9d640d5efd9a140a6bda8da53b220aa258167993
F src/vdbeaux.c f0e7cfa04f7ac44d69866868531dbaf20659d0a2
F src/vdbeblob.c 37c3d11a753e403698c69e17383d282e1ae73e75
F src/vdbeaux.c 23b38b447ebf5991de1d3d456003c58cf523a5da
F src/vdbeblob.c 3b570b730109e8f653d9d2081649f6e7015113db
F src/vdbemem.c b9181e77eca2a095929d46250daf85c8d2621fc0
F src/vdbesort.c ef3c6d1f1a7d44cf67bb2bee59ea3d1fe5bad174
F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484
@ -1423,7 +1423,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 62ea9e5ab8bc1a20245beebceb5ea62dcd7ec84e
R e3a290a62981c78902a14c3c2f0729a7
U dan
Z 6792ae7332aab4430b100fd43f303a7d
P 063755c81574800e7db12a42e17d982a8c1e5181
R 03bd7861865ae8f6fba63605b50d909b
U drh
Z 0f50d7954b5cdd37df3317e2f95eccf8

View File

@ -1 +1 @@
063755c81574800e7db12a42e17d982a8c1e5181
ae8b9d2edf1b5aef6108e729754911db7682b6a3

View File

@ -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

View File

@ -1599,16 +1599,15 @@ void sqlite3Pragma(
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
{ OP_AddImm, 1, 0, 0}, /* 0 */
{ OP_If, 1, 0, 0}, /* 1 */
{ OP_If, 1, 4, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0},
{ OP_ResultRow, 3, 1, 0}, /* 3 */
};
VdbeOp *aOp;
aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
if( aOp ){
aOp[0].p2 = -mxErr;
aOp[1].p2 = sqlite3VdbeCurrentAddr(v);
aOp[2].p4type = P4_STATIC;
aOp[2].p4.z = "ok";
}

View File

@ -2641,7 +2641,7 @@ struct SelectDest {
** 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
** information in case inserts are done within triggers. Triggers do not
** normally coordinate their activities, but we do need to coordinate the
** loading and saving of autoincrement information.
*/

View File

@ -646,6 +646,9 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
/*
** Add a whole list of operations to the operation stack. Return a
** pointer to the first operation inserted.
**
** Non-zero P2 arguments to jump instructions are automatically adjusted
** so that the jump target is relative to the first operation inserted.
*/
VdbeOp *sqlite3VdbeAddOpList(
Vdbe *p, /* Add opcodes to the prepared statement */
@ -666,6 +669,9 @@ VdbeOp *sqlite3VdbeAddOpList(
pOut->p1 = aOp->p1;
pOut->p2 = aOp->p2;
assert( aOp->p2>=0 );
if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){
pOut->p2 += p->nOp;
}
pOut->p3 = aOp->p3;
pOut->p4type = P4_NOTUSED;
pOut->p4.p = 0;

View File

@ -249,19 +249,17 @@ int sqlite3_blob_open(
** which closes the b-tree cursor and (possibly) commits the
** transaction.
*/
static const int iLn = VDBE_OFFSET_LINENO(4);
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList openBlob[] = {
/* addr/ofst */
/* {OP_Transaction, 0, 0, 0}, // 0/ inserted separately */
{OP_TableLock, 0, 0, 0}, /* 1/0: Acquire a read or write lock */
{OP_OpenRead, 0, 0, 0}, /* 2/1: Open a cursor */
{OP_Variable, 1, 1, 0}, /* 3/2: Move ?1 into reg[1] */
{OP_NotExists, 0, 8, 1}, /* 4/3: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 5/4 */
{OP_ResultRow, 1, 0, 0}, /* 6/5 */
{OP_Goto, 0, 3, 0}, /* 7/6 */
{OP_Close, 0, 0, 0}, /* 8/7 */
{OP_Halt, 0, 0, 0}, /* 9/8 */
{OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */
{OP_OpenRead, 0, 0, 0}, /* 1: Open a cursor */
{OP_Variable, 1, 1, 0}, /* 2: Move ?1 into reg[1] */
{OP_NotExists, 0, 7, 1}, /* 3: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 4 */
{OP_ResultRow, 1, 0, 0}, /* 5 */
{OP_Goto, 0, 2, 0}, /* 6 */
{OP_Close, 0, 0, 0}, /* 7 */
{OP_Halt, 0, 0, 0}, /* 8 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);