-C Fix\sa\sproblem\spreventing\sUPDATE\sstatements\sthat\suse\sa\srange-scan\son\sthe\sPK\nindex\sof\sa\sWITHOUT\sROWID\stable\sfrom\susing\sa\sone-pass\sstrategy.
-D 2017-01-11T15:42:14.353
+C Fix\sa\sproblem\swith\ssingle-pass\smulti-row\sUPDATE\sstatements\sthat\sinvoke\sREPLACE\nconflict\shandling.
+D 2017-01-11T19:03:08.308
F Makefile.in 41bd4cad981487345c4a84081074bcdb876e4b2e
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
F src/tokenize.c 5c2f516876fc27fbd7753913f032f49eb89e83b5
F src/treeview.c 4e44ade3bfe59d82005039f72e09333ce2b4162c
F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182
-F src/update.c 117bb080654b8c382b590b369f174ec11cca5bb0
+F src/update.c 4ed0fcccccd6488ee8a3bc02df10979b503f25d7
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
F src/util.c a88b0466fddf445ce752226d4698ca3faada620a
F src/vacuum.c 33c174b28886b2faf26e503b5a49a1c01a9b1c16
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32
-F test/update2.test 2b678973f882d11496f998c01b310be4c4a65a70
+F test/update2.test 7f72ef307d58be09a8ef61db23a7ef60e5af019d
F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 46db23ccd116ce5b9d949f9293be8a2818411b46
-R a3998d49adecb7e21ad8d0444ff44124
+P cab86c90945126c24c40cf2dedd053a8c46d00d6
+R 91b60fc45aced248f038aee86694df0e
U dan
-Z c5a6bc3f18beb290c2a3c904ee96a0c7
+Z f69bdc261645bb06f02a001c239441ef
-cab86c90945126c24c40cf2dedd053a8c46d00d6
\ No newline at end of file
+0a2b8e1b9dc600b5a93622e8eea6218649df5e0f
\ No newline at end of file
int addrOpen; /* Address of OP_OpenEphemeral */
int iPk; /* First of nPk cells holding PRIMARY KEY value */
i16 nPk; /* Number of components of the PRIMARY KEY */
+ int bReplace = 0; /* True if REPLACE conflict resolution might happen */
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
reg = ++pParse->nMem;
pParse->nMem += pIdx->nColumn;
+ if( (onError==OE_Replace)
+ || (onError==OE_Default && pIdx->onError==OE_Replace)
+ ){
+ bReplace = 1;
+ }
break;
}
}
if( reg==0 ) aToOpen[j+1] = 0;
aRegIdx[j] = reg;
}
+ if( bReplace ){
+ /* If REPLACE conflict resolution might be invoked, open cursors on all
+ ** indexes in case they are needed to delete records. */
+ memset(aToOpen, 1, nIdx+1);
+ }
/* Begin generating code. */
v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
}
- /* Begin the database scan. */
+ /* Begin the database scan.
+ **
+ ** Do not consider a single-pass strategy for a multi-row update if
+ ** there are any triggers or foreign keys to process, or rows may
+ ** be deleted as a result of REPLACE conflict handling. Any of these
+ ** things might disturb a cursor being used to scan through the table
+ ** or index, causing a single-pass approach to malfunction. */
flags = WHERE_ONEPASS_DESIRED | WHERE_SEEK_TABLE;
- if( pParse->nested==0 && pTrigger==0 && hasFK==0 && chngKey==0 ){
+ if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
labelBreak = sqlite3VdbeMakeLabel(v);
if( !isView ){
- int iAddrOnce = 0;
- /*
- ** Open every index that needs updating. Note that if any
- ** index could potentially invoke a REPLACE conflict resolution
- ** action, then we need to open all indices because we might need
- ** to be deleting some records.
- */
- if( onError==OE_Replace ){
- memset(aToOpen, 1, nIdx+1);
- }else{
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_Replace ){
- memset(aToOpen, 1, nIdx+1);
- break;
- }
- }
- }
+ int addrOnce = 0;
+
+ /* Open every index that needs updating. */
if( eOnePass!=ONEPASS_OFF ){
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
}
if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
- iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen,
0, 0);
- if( iAddrOnce ) sqlite3VdbeJumpHere(v, iAddrOnce);
+ if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
}
/* Top of the update loop */
if( !isView ){
int addr1 = 0; /* Address of jump instruction */
- int bReplace = 0; /* True if REPLACE conflict resolution might happen */
/* Do constraint checks. */
assert( regOldRowid>0 );
#-------------------------------------------------------------------------
#
foreach {tn sql} {
- 1 { CREATE TABLE b1(a INTEGER PRIMARY KEY, b, c) }
- 2 { CREATE TABLE b1(a INT PRIMARY KEY, b, c) WITHOUT ROWID }
+ 1 {
+ CREATE TABLE b1(a INTEGER PRIMARY KEY, b, c);
+ CREATE TABLE c1(a INTEGER PRIMARY KEY, b, c, d)
+ }
+ 2 {
+ CREATE TABLE b1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
+ CREATE TABLE c1(a INT PRIMARY KEY, b, c, d) WITHOUT ROWID;
+ }
} {
- execsql { DROP TABLE IF EXISTS b1 }
+ execsql { DROP TABLE IF EXISTS b1; DROP TABLE IF EXISTS c1; }
execsql $sql
+
do_execsql_test 4.$tn.0 {
CREATE UNIQUE INDEX b1c ON b1(c);
-
INSERT INTO b1 VALUES(1, 'a', 1);
INSERT INTO b1 VALUES(2, 'b', 15);
INSERT INTO b1 VALUES(3, 'c', 3);
6 f 16
7 g 17
}
-}
+ do_execsql_test 4.$tn.2 {
+ CREATE INDEX c1d ON c1(d, b);
+ CREATE UNIQUE INDEX c1c ON c1(c, b);
+
+ INSERT INTO c1 VALUES(1, 'a', 1, 1);
+ INSERT INTO c1 VALUES(2, 'a', 15, 2);
+ INSERT INTO c1 VALUES(3, 'a', 3, 3);
+ INSERT INTO c1 VALUES(4, 'a', 4, 4);
+ INSERT INTO c1 VALUES(5, 'a', 5, 5);
+ INSERT INTO c1 VALUES(6, 'a', 6, 6);
+ INSERT INTO c1 VALUES(7, 'a', 7, 7);
+ }
+
+ do_execsql_test 4.$tn.3 {
+ UPDATE OR REPLACE c1 SET c=c+10 WHERE d BETWEEN 4 AND 7;
+ SELECT * FROM c1 ORDER BY a;
+ } {
+ 1 a 1 1
+ 3 a 3 3
+ 4 a 14 4
+ 5 a 15 5
+ 6 a 16 6
+ 7 a 17 7
+ }
+
+ do_execsql_test 4.$tn.4 { PRAGMA integrity_check } ok
+
+ do_execsql_test 4.$tn.5 {
+ DROP INDEX c1d;
+ DROP INDEX c1c;
+ DELETE FROM c1;
+
+ INSERT INTO c1 VALUES(1, 'a', 1, 1);
+ INSERT INTO c1 VALUES(2, 'a', 15, 2);
+ INSERT INTO c1 VALUES(3, 'a', 3, 3);
+ INSERT INTO c1 VALUES(4, 'a', 4, 4);
+ INSERT INTO c1 VALUES(5, 'a', 5, 5);
+ INSERT INTO c1 VALUES(6, 'a', 6, 6);
+ INSERT INTO c1 VALUES(7, 'a', 7, 7);
+
+ CREATE INDEX c1d ON c1(d);
+ CREATE UNIQUE INDEX c1c ON c1(c);
+ }
+
+ do_execsql_test 4.$tn.6 {
+ UPDATE OR REPLACE c1 SET c=c+10 WHERE d BETWEEN 4 AND 7;
+ SELECT * FROM c1 ORDER BY a;
+ } {
+ 1 a 1 1
+ 3 a 3 3
+ 4 a 14 4
+ 5 a 15 5
+ 6 a 16 6
+ 7 a 17 7
+ }
+}
finish_test
+