Also allow UPDATE on virtual tables to use the onepass strategy.

FossilOrigin-Name: 1aa27d706db9b2e21737ce4b94b47ecd12c2570f
This commit is contained in:
dan
2015-09-28 20:03:49 +00:00
parent d943b27596
commit 0f40037eee
6 changed files with 121 additions and 92 deletions
+1 -1
View File
@@ -874,7 +874,7 @@ static int fts3PendingTermsDocid(
** generate longer doclists.
*/
if( iDocid<p->iPrevDocid
|| (iDocid==p->iPrevLangid && p->bPrevDelete==0)
|| (iDocid==p->iPrevDocid && p->bPrevDelete==0)
|| p->iPrevLangid!=iLangid
|| p->nPendingData>p->nMaxPendingData
){
+9 -9
View File
@@ -1,5 +1,5 @@
C Update\sfts3\sto\suse\sthe\sonepass\sstrategy\sfor\sdelete\soperations.
D 2015-09-28T15:23:29.191
C Also\sallow\sUPDATE\son\svirtual\stables\sto\suse\sthe\sonepass\sstrategy.
D 2015-09-28T20:03:49.551
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2143eeef6d0cc26006ae5fc4bb242a4a8b973412
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c a93f5edc0aff44ef8b06d7cb55b52026541ca145
F ext/fts3/fts3_unicode2.c c3d01968d497bd7001e7dc774ba75b372738c057
F ext/fts3/fts3_write.c 5d7857a6a454f210e4fabc2528e8a63e6ab98078
F ext/fts3/fts3_write.c 6f7233a06df17084d5cd968899053731bf953f94
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3view.c 8e53d0190a7b3443764bbd32ad47be2bd852026d
@@ -399,7 +399,7 @@ F src/threads.c bbfb74450643cb5372a43ad4f6cffd7e9dfcecb0
F src/tokenize.c 83c6ed569423a3af83a83973b444cf7123be33a6
F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
F src/update.c eb7ab3ff2928628692a4f14be397c95f4a681d97
F src/update.c 779319e1d52c3dfb3b870c9acd26161b464fbe27
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
@@ -690,7 +690,7 @@ F test/fts3aux2.test 7ae2b2c13aefdf4169279a27a5f51780ce57f6ba
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
F test/fts3conf.test 92bc4cc67f948b2f53f73c8ab0ebf4be9eee92aa
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
@@ -727,7 +727,7 @@ F test/fts4aa.test 10aac8e9d62c7357590acfabe3fad01e9a9ce1cb
F test/fts4check.test 9d9e818fd6cb29c0e007cd6d00447739d4fde430
F test/fts4content.test abb0c77bc3da3df64fec72e00844d2257a90025d
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
F test/fts4growth.test a73eab34dd9960d10603347fc77fefe2f9322e26
F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53
F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d
F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
@@ -1388,7 +1388,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P e73f919fae1833c6ffb36eddbc76d9a8d9324214
R 164b44f729dee0c8bb93a44bcf38cdec
P fffab4f70f85eeb2acbb89534064a6e397c39384
R 57289d0ecbc93a6cd377511502833368
U dan
Z 708fbaf265cb02c74fec8f06c877c6ce
Z 186d4cd8527ef990e771b3fd7444e8fc
+1 -1
View File
@@ -1 +1 @@
fffab4f70f85eeb2acbb89534064a6e397c39384
1aa27d706db9b2e21737ce4b94b47ecd12c2570f
+103 -74
View File
@@ -300,29 +300,20 @@ void sqlite3Update(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Virtual tables must be handled separately */
if( IsVirtual(pTab) ){
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
pWhere, onError);
pWhere = 0;
pTabList = 0;
goto update_cleanup;
}
#endif
/* Allocate required registers. */
regRowSet = ++pParse->nMem;
regOldRowid = regNewRowid = ++pParse->nMem;
if( chngPk || pTrigger || hasFK ){
regOld = pParse->nMem + 1;
if( !IsVirtual(pTab) ){
regRowSet = ++pParse->nMem;
regOldRowid = regNewRowid = ++pParse->nMem;
if( chngPk || pTrigger || hasFK ){
regOld = pParse->nMem + 1;
pParse->nMem += pTab->nCol;
}
if( chngKey || pTrigger || hasFK ){
regNewRowid = ++pParse->nMem;
}
regNew = pParse->nMem + 1;
pParse->nMem += pTab->nCol;
}
if( chngKey || pTrigger || hasFK ){
regNewRowid = ++pParse->nMem;
}
regNew = pParse->nMem + 1;
pParse->nMem += pTab->nCol;
/* Start the view context. */
if( isView ){
@@ -345,6 +336,15 @@ void sqlite3Update(
goto update_cleanup;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Virtual tables must be handled separately */
if( IsVirtual(pTab) ){
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
pWhere, onError);
goto update_cleanup;
}
#endif
/* Begin the database scan
*/
if( HasRowid(pTab) ){
@@ -685,21 +685,23 @@ update_cleanup:
/*
** Generate code for an UPDATE of a virtual table.
**
** The strategy is that we create an ephemeral table that contains
** There are two possible strategies - the default and the special
** "onepass" strategy. Onepass is only used if the virtual table
** implementation indicates that pWhere may match at most one row.
**
** The default strategy is to create an ephemeral table that contains
** for each row to be changed:
**
** (A) The original rowid of that row.
** (B) The revised rowid for the row. (note1)
** (B) The revised rowid for the row.
** (C) The content of every column in the row.
**
** Then we loop over this ephemeral table and for each row in
** the ephemeral table call VUpdate.
** Then loop through the contents of this ephemeral table executing a
** VUpdate for each row. When finished, drop the ephemeral table.
**
** When finished, drop the ephemeral table.
**
** (note1) Actually, if we know in advance that (A) is always the same
** as (B) we only store (A), then duplicate (A) when pulling
** it out of the ephemeral table before calling VUpdate.
** The "onepass" strategy does not use an ephemeral table. Instead, it
** stores the same values (A, B and C above) in a register array and
** makes a single invocation of VUpdate.
*/
static void updateVirtualTable(
Parse *pParse, /* The parsing context */
@@ -712,65 +714,92 @@ static void updateVirtualTable(
int onError /* ON CONFLICT strategy */
){
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
ExprList *pEList = 0; /* The result set of the SELECT statement */
Select *pSelect = 0; /* The SELECT statement */
Expr *pExpr; /* Temporary expression */
int ephemTab; /* Table holding the result of the SELECT */
int i; /* Loop counter */
int addr; /* Address of top of loop */
int iReg; /* First register in set passed to OP_VUpdate */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
SelectDest dest;
WhereInfo *pWInfo;
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
int regRowid; /* Register for ephem table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
int bOnePass; /* True to use onepass strategy */
int addr; /* Address of OP_OpenEphemeral */
NameContext sNC;
/* Construct the SELECT statement that will find the new values for
** all updated rows.
*/
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, "_rowid_"));
if( pRowid ){
pEList = sqlite3ExprListAppend(pParse, pEList,
sqlite3ExprDup(db, pRowid, 0));
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
}else{
pExpr = sqlite3Expr(db, TK_ID, pTab->aCol[i].zName);
}
pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
}
pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
/* Create the ephemeral table into which the update results will
** be stored.
*/
/* Allocate nArg registers to martial the arguments to VUpdate. Then
** create and open the ephemeral table in which the records created from
** these arguments will be temporarily stored. */
assert( v );
ephemTab = pParse->nTab++;
addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
regArg = pParse->nMem + 1;
pParse->nMem += nArg;
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
/* fill the ephemeral table
*/
sqlite3SelectDestInit(&dest, SRT_EphemTab, ephemTab);
sqlite3Select(pParse, pSelect, &dest);
/* Start scanning the virtual table */
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
if( pWInfo==0 ) return;
/* Generate code to scan the ephemeral table and call VUpdate. */
iReg = ++pParse->nMem;
pParse->nMem += pTab->nCol+1;
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
/* Populate the argument registers. */
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
if( pRowid ){
sqlite3ExprCode(pParse, pRowid, regArg+1);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
}
for(i=0; i<pTab->nCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
}else{
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
}
}
bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
if( bOnePass ){
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
** above. Also, if this is a top-level parse (not a trigger), clear the
** multi-write flag so that the VM does not open a statement journal */
sqlite3VdbeChangeToNoop(v, addr);
if( sqlite3ParseToplevel(pParse)==pParse ){
pParse->isMultiWrite = 0;
}
}else{
/* Create a record from the argument register contents and insert it into
** the ephemeral table. */
sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
}
/* End the virtual table scan */
sqlite3WhereEnd(pWInfo);
if( bOnePass==0 ){
/* Begin scannning through the ephemeral table. */
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); VdbeCoverage(v);
/* Extract arguments from the current row of the ephemeral table and
** invoke the VUpdate method. */
for(i=0; i<nArg; i++){
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i);
}
}
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
/* Cleanup */
sqlite3SelectDelete(db, pSelect);
/* End of the ephemeral table scan */
if( bOnePass==0 ){
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
}
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+5 -5
View File
@@ -86,11 +86,11 @@ foreach {tn sql uses constraint data} [subst {
9 "INSERT OR IGNORE $T2" 1 0 {{a b c d} {e f g h} {i j k l} z}
10 "INSERT OR REPLACE $T2" 1 0 {{a b c d} y {i j k l} z}
11 "UPDATE OR ROLLBACK $T3" 1 1 {{a b c d} {e f g h}}
12 "UPDATE OR ABORT $T3" 1 1 {{a b c d} {e f g h} {i j k l}}
13 "UPDATE OR FAIL $T3" 1 1 {{a b c d} {e f g h} {i j k l}}
14 "UPDATE OR IGNORE $T3" 1 0 {{a b c d} {e f g h} {i j k l}}
15 "UPDATE OR REPLACE $T3" 1 0 {{a b c d} {i j k l}}
11 "UPDATE OR ROLLBACK $T3" 0 1 {{a b c d} {e f g h}}
12 "UPDATE OR ABORT $T3" 0 1 {{a b c d} {e f g h} {i j k l}}
13 "UPDATE OR FAIL $T3" 0 1 {{a b c d} {e f g h} {i j k l}}
14 "UPDATE OR IGNORE $T3" 0 0 {{a b c d} {e f g h} {i j k l}}
15 "UPDATE OR REPLACE $T3" 0 0 {{a b c d} {i j k l}}
16 "UPDATE OR ROLLBACK $T4" 1 1 {{a b c d} {e f g h}}
17 "UPDATE OR ABORT $T4" 1 1 {{a b c d} {e f g h} {i j k l}}
+2 -2
View File
@@ -202,11 +202,11 @@ do_test 3.1.3 {
delete_doc 9 8 7
}
execsql { SELECT level, idx, second(end_block) FROM x3_segdir }
} {0 0 591 0 1 72 0 2 76}
} {0 0 591 0 1 65 0 2 72 0 3 76}
do_test 3.1.4 {
execsql { INSERT INTO x3(x3) VALUES('optimize') }
execsql { SELECT level, idx, second(end_block) FROM x3_segdir }
} {0 0 463}
} {0 0 412}
do_test 3.2.1 {
execsql { DELETE FROM x3 }