Add the OP_FinishSeek opcode which completes an OP_DeferredSeek if the seek
has not already completed. Also add the sqlite3WhereUsesDeferredSeek() interface to the query planner. The UPDATE implementation adds an OP_FinishSeek before running the final OP_Insert if one is needed. Ticket [ec8abb025e78f40c] and also an assertion fault reported by Yongheng. FossilOrigin-Name: 21ef6e99331210b80fa7c71b4f02e8f768a748d01aef884368af2f6b51a067e0
This commit is contained in:
parent
997d7434b7
commit
be3da24134
32
manifest
32
manifest
@ -1,5 +1,5 @@
|
||||
C Do\snot\sattempt\sto\sflatten\scompound\ssub-queries\sin\sa\sFROM\sclause\sinto\sthe\sparent\sif\sany\scomponent\sof\sthe\ssub-query\suses\sa\swindow\sfunction.
|
||||
D 2019-12-28T18:25:51.300
|
||||
C Add\sthe\sOP_FinishSeek\sopcode\swhich\scompletes\san\sOP_DeferredSeek\sif\sthe\sseek\nhas\snot\salready\scompleted.\s\sAlso\sadd\sthe\ssqlite3WhereUsesDeferredSeek()\ninterface\sto\sthe\squery\splanner.\s\sThe\sUPDATE\simplementation\sadds\san\nOP_FinishSeek\sbefore\srunning\sthe\sfinal\sOP_Insert\sif\sone\sis\sneeded.\nTicket\s[ec8abb025e78f40c]\sand\salso\san\sassertion\sfault\sreported\sby\sYongheng.
|
||||
D 2019-12-29T00:52:41.688
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -469,7 +469,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/backup.c f70077d40c08b7787bfe934e4d1da8030cb0cc57d46b345fba2294b7d1be23ab
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 695bcbc62177cf70faaf6b34f89c22415e5581a13c57d67c862057636d3f09b9
|
||||
F src/btree.c e03085a75c1d6cd1db7f458a6e09d7111a4ebe4b7490aafc833ec714158ffdb1
|
||||
F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484
|
||||
F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437
|
||||
F src/build.c 5aa8776d926954f13ddc37144c765ff8d80e49b74432c0f5a10f29433f0d69a8
|
||||
@ -533,7 +533,7 @@ F src/shell.c.in 4a3a9e1c11847b1904f2b01d087af1c052f660902755abab457cab1756817de
|
||||
F src/sqlite.h.in 2a23e8161775253d9cf383c2c6aa559005dc787d350dcb0be67a6c4cc3bd1d19
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 72af51aa4e912e14cd495fb6e7fac65f0940db80ed950d90911aff292cc47ce2
|
||||
F src/sqliteInt.h 3e235c7a406630bff9fe7183d9af5d4ce21a9b7acb77bf1b82a0caa130a5f687
|
||||
F src/sqliteInt.h dcd5b4b29596cb5969586790ae45f75fe8deaf5fde1a90d572ad12b2f970b318
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -595,16 +595,16 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d
|
||||
F src/treeview.c 7a8097cff1584acd0a228817103513bf1d1bf5ba91ff142b99c83e406c0968f3
|
||||
F src/trigger.c 681ccdb910a87243940d63f99b26190d9c5d2534c2ded3c0825b7c0e315a342e
|
||||
F src/update.c aed4261a7854ff3031c0d361b04988c8dce5b845a3fb3999fedc51140a836e78
|
||||
F src/update.c fae1082d3e28a13a4d4ed7ac35eaeb2f746d736882e46dd653671ab64396d86b
|
||||
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
|
||||
F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
|
||||
F src/util.c 2c92bc706bbdb1c45a25180291e7e05a56e297aa5dd7b2bcd2b1c47e8bb05b17
|
||||
F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
|
||||
F src/vdbe.c 4d91d635d7aff34e09fade185911c7980fc42f93cc7b18f5387fad5a1166f08c
|
||||
F src/vdbe.c 7235823bf9ec3ea298cc5c5e832c026d1cb4838c7507cdf28bf97c829353876a
|
||||
F src/vdbe.h 3f068f00b23aebf392df142312ab5874588371c6d83e60d953f6d6b6453491c5
|
||||
F src/vdbeInt.h 1ccaf470287e2d153b16cf7b0274d436db2c2f74cdf14afd1a0ff4cb51548ae6
|
||||
F src/vdbeInt.h e02ccac0334f7c71c952210657e6e18de1917605887c7bc6167a80a17f62da18
|
||||
F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02
|
||||
F src/vdbeaux.c e041d20b5000abbd651f7d470c66eaa13e868f58a13c1a940b4d426c6d0d43b5
|
||||
F src/vdbeaux.c 0a9716e47012ef018038c2e1dab9f701a6fb4429bb3ee1d4d0f49497519ace74
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
F src/vdbemem.c fa083086758379b52f8771d69424b273c7bd0f94413802404ee32cd5cc7cd870
|
||||
F src/vdbesort.c a3be032cc3fee0e3af31773af4a7a6f931b7230a34f53282ccf1d9a2a72343be
|
||||
@ -614,9 +614,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 15a2845769f51ba132f9cf0b2c7a6887a91fc8437892dbcce9fcdc68b66d60a1
|
||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
||||
F src/walker.c a137468bf36c92e64d2275caa80c83902e3a0fc59273591b96c6416d3253d05d
|
||||
F src/where.c 7bb294fdada405412dfd76d351286e0dec3dda07a8e19b0f904b8e8fc0ced41f
|
||||
F src/whereInt.h de1b77e416ad5a7cc60a71fc1317484f8d83ca1e52b805dc8c978785a92eeded
|
||||
F src/wherecode.c 3c9b185cdb6950fa1043d324d3e8ef14b07cef4f5cfb475611b6f43480494fb2
|
||||
F src/where.c 602e5093556bbd9090c0a9bd834fec0717e3a4b0377a021d38091a6d554a1177
|
||||
F src/whereInt.h a727b32260e12707a8c1bc29d7f7e9b6dc1a44551a45093d5968fbe570ff0c56
|
||||
F src/wherecode.c a987d22b42e09b06f3a49596e0953b1cd28e568cc656681776edc0026cfac0cc
|
||||
F src/whereexpr.c 4b34be1434183e7bb8a05d4bf42bd53ea53021b0b060936fbd12062b4ff6b396
|
||||
F src/window.c 87795bb8293179cb8a92529264d49bd66b5bcad5e91cfc17dd8d3e66a2a77f88
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
@ -1605,7 +1605,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
|
||||
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
|
||||
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
|
||||
F test/update.test 6fdd76fdf3194fb10ee184b3b2999c61d10d2a0b825dbcaa2d08ff394f3e26e3
|
||||
F test/update.test 40aa53edd597a4cf16bca3890f429a91999ad7885117918ec8fc9d5d8b41d104
|
||||
F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3
|
||||
F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18
|
||||
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
|
||||
@ -1853,7 +1853,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 82be135dee7ccfde5f8a67f3621b7ced449dce89bae9cadf025154a4de848c11
|
||||
R 689fc9af6e2b279bc6d7fd22df0aa0f5
|
||||
U dan
|
||||
Z 819583b2c969ec1f752f2ef5cdcbf2f5
|
||||
P eeb76f621de2f930a548db0fbb9fe25b4479b73581826b8dfa2e63cd1f1ab783
|
||||
R af3bb40e1df9ee06fcab6108c3a14e15
|
||||
U drh
|
||||
Z da1bc4514591aa0f5f1f69cf011c69ab
|
||||
|
@ -1 +1 @@
|
||||
eeb76f621de2f930a548db0fbb9fe25b4479b73581826b8dfa2e63cd1f1ab783
|
||||
21ef6e99331210b80fa7c71b4f02e8f768a748d01aef884368af2f6b51a067e0
|
@ -8658,7 +8658,6 @@ int sqlite3BtreeInsert(
|
||||
if( flags & BTREE_SAVEPOSITION ){
|
||||
assert( pCur->curFlags & BTCF_ValidNKey );
|
||||
assert( pX->nKey==pCur->info.nKey );
|
||||
assert( pCur->info.nSize!=0 );
|
||||
assert( loc==0 );
|
||||
}
|
||||
#endif
|
||||
|
@ -4115,6 +4115,7 @@ int sqlite3WhereOkOnePass(WhereInfo*, int*);
|
||||
#define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */
|
||||
#define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */
|
||||
#define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */
|
||||
int sqlite3WhereUsesDeferredSeek(WhereInfo*);
|
||||
void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
|
||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
|
||||
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||
|
25
src/update.c
25
src/update.c
@ -191,6 +191,7 @@ void sqlite3Update(
|
||||
int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */
|
||||
i16 nPk = 0; /* Number of components of the PRIMARY KEY */
|
||||
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
|
||||
int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */
|
||||
|
||||
/* Register Allocations */
|
||||
int regRowCount = 0; /* A count of rows changed */
|
||||
@ -524,6 +525,7 @@ void sqlite3Update(
|
||||
pWInfo = 0;
|
||||
eOnePass = ONEPASS_SINGLE;
|
||||
sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
|
||||
bFinishSeek = 0;
|
||||
}else{
|
||||
/* Begin the database scan.
|
||||
**
|
||||
@ -550,6 +552,7 @@ void sqlite3Update(
|
||||
** strategy that uses an index for which one or more columns are being
|
||||
** updated. */
|
||||
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
||||
bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
|
||||
if( eOnePass!=ONEPASS_SINGLE ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
if( eOnePass==ONEPASS_MULTI ){
|
||||
@ -713,6 +716,7 @@ void sqlite3Update(
|
||||
testcase( i==31 );
|
||||
testcase( i==32 );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
|
||||
bFinishSeek = 0;
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, k);
|
||||
}
|
||||
@ -800,21 +804,14 @@ void sqlite3Update(
|
||||
/* Delete the index entries associated with the current record. */
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
|
||||
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
/* If pTab contains one or more virtual columns, then it is possible
|
||||
** (though unlikely) that no OP_Column opcodes have been run against
|
||||
** the table since the OP_SeekDeferred, meaning that there has not been
|
||||
** a seek against the cursor yet. The OP_Delete opcode and OP_Insert
|
||||
** opcodes that follow will be needing this seek, so code a bogus
|
||||
** OP_Column just to make sure the seek has been done.
|
||||
** See ticket ec8abb025e78f40c 2019-12-26
|
||||
*/
|
||||
if( eOnePass!=ONEPASS_OFF && (pTab->tabFlags & TF_HasVirtual)!=0 ){
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iDataCur, 0, r1);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
||||
/* We must run the OP_FinishSeek opcode to resolve a prior
|
||||
** OP_DeferredSeek if there is any possibility that there have been
|
||||
** no OP_Column opcodes since the OP_DeferredSeek was issued. But
|
||||
** we want to avoid the OP_FinishSeek if possible, as running it
|
||||
** costs CPU cycles. */
|
||||
if( bFinishSeek ){
|
||||
sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
|
||||
|
||||
/* If changing the rowid value, or if there are foreign key constraints
|
||||
** to process, delete the old record. Otherwise, add a noop OP_Delete
|
||||
|
19
src/vdbe.c
19
src/vdbe.c
@ -4827,6 +4827,7 @@ case OP_Insert: {
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
|
||||
assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
|
||||
@ -5700,6 +5701,24 @@ case OP_IdxRowid: { /* out2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: FinishSeek P1 * * * *
|
||||
**
|
||||
** If cursor P1 was previously moved via OP_DeferredSeek, complete that
|
||||
** seek operation now, without further delay. If the cursor seek has
|
||||
** already occurred, this instruction is a no-op.
|
||||
*/
|
||||
case OP_FinishSeek: {
|
||||
VdbeCursor *pC; /* The P1 index cursor */
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC->deferredMoveto ){
|
||||
rc = sqlite3VdbeFinishMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxGE P1 P2 P3 P4 P5
|
||||
** Synopsis: key=r[P3@P4]
|
||||
**
|
||||
|
@ -483,6 +483,7 @@ struct PreUpdate {
|
||||
void sqlite3VdbeError(Vdbe*, const char *, ...);
|
||||
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor*);
|
||||
u32 sqlite3VdbeSerialTypeLen(u32);
|
||||
|
@ -3414,7 +3414,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
** carried out. Seek the cursor now. If an error occurs, return
|
||||
** the appropriate error code.
|
||||
*/
|
||||
static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
|
||||
int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
|
||||
int res, rc;
|
||||
#ifdef SQLITE_TEST
|
||||
extern int sqlite3_search_count;
|
||||
@ -3486,7 +3486,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
||||
*piCol = iMap - 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return handleDeferredMoveto(p);
|
||||
return sqlite3VdbeFinishMoveto(p);
|
||||
}
|
||||
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
||||
return handleMovedCursor(p);
|
||||
|
10
src/where.c
10
src/where.c
@ -120,7 +120,7 @@ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
|
||||
|
||||
/*
|
||||
** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
|
||||
** operate directly on the rowis returned by a WHERE clause. Return
|
||||
** operate directly on the rowids returned by a WHERE clause. Return
|
||||
** ONEPASS_SINGLE (1) if the statement can operation directly because only
|
||||
** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass
|
||||
** optimization can be used on multiple
|
||||
@ -147,6 +147,14 @@ int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
|
||||
return pWInfo->eOnePass;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move
|
||||
** the data cursor to the row selected by the index cursor.
|
||||
*/
|
||||
int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){
|
||||
return pWInfo->bDeferredSeek;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the content of pSrc into pDest
|
||||
*/
|
||||
|
@ -459,6 +459,7 @@ struct WhereInfo {
|
||||
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
|
||||
u8 sorted; /* True if really sorted (not just grouped) */
|
||||
u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
|
||||
u8 bDeferredSeek; /* Uses OP_DeferredSeek */
|
||||
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
|
||||
u8 eDistinct; /* One of the WHERE_DISTINCT_* values */
|
||||
u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */
|
||||
|
@ -1045,6 +1045,7 @@ static void codeDeferredSeek(
|
||||
assert( iIdxCur>0 );
|
||||
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
|
||||
|
||||
pWInfo->bDeferredSeek = 1;
|
||||
sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
|
||||
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|
||||
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
|
||||
|
@ -684,4 +684,21 @@ do_execsql_test update-18.20 {
|
||||
SELECT * FROM t0;
|
||||
} {0 0}
|
||||
|
||||
# 2019-12-28 assertion fault reported by Yongheng
|
||||
# Similar to ticket ec8abb025e78f40c
|
||||
# An UPDATE was reaching the OP_Delete after running OP_DeferredSeek
|
||||
# without ever hitting an OP_Column. The enhanced solution is to
|
||||
# fix OP_Delete so that it can do the seek itself.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test update-19.10 {
|
||||
CREATE TABLE t1(
|
||||
a TEXT,
|
||||
b INTEGER PRIMARY KEY UNIQUE
|
||||
);
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
UPDATE t1 SET a = quote(b) WHERE b>=2;
|
||||
SELECT * FROM t1;
|
||||
} {2 2}
|
||||
|
||||
finish_test
|
||||
|
Loading…
x
Reference in New Issue
Block a user