From: dan Date: Tue, 5 Nov 2013 16:39:31 +0000 (+0000) Subject: Unless the destination table is completely empty, disable the xfer optimization for... X-Git-Tag: version-3.8.2~137^2~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=427ebba10cd97f34141fceb7c38483c5ccda702f;p=thirdparty%2Fsqlite.git Unless the destination table is completely empty, disable the xfer optimization for WITHOUT ROWID tables. FossilOrigin-Name: 3877c9f50582b51817dcf3cd75d836891a34e590 --- diff --git a/manifest b/manifest index 6a2b361195..a63c3a2179 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\sbackcompat.test\stest\sscript\sso\sthat\sit\sworks\swith\sreally\sold\s(3.6.*)\sversions. -D 2013-11-05T15:02:39.443 +C Unless\sthe\sdestination\stable\sis\scompletely\sempty,\sdisable\sthe\sxfer\soptimization\sfor\sWITHOUT\sROWID\stables. +D 2013-11-05T16:39:31.103 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 37bbaf90c077a8a8a6a5831d66c223b66e8272ae +F src/insert.c 7559252147d3aad55951ecd5fadf8350729cb901 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b @@ -831,7 +831,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 0a48d94222d50e6e50d72ac103606c4f8e7cbb81 -F test/tester.tcl 901258f2825cb712be4093bcd9317082d26a9901 +F test/tester.tcl b95c4e385003665c729bed9dbd385c42c80daeef F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1078,7 +1078,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b -F test/without_rowid1.test 0b349aa31554afcee213ccabf4d259f4ff13a86a +F test/without_rowid1.test ba137a86e4dcd23c72b6fce8ee4cee98cbf27784 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a @@ -1133,7 +1133,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 99b1fa4b1664a79eae1dddce2b9a848384cdb1d7 -R 9237f8c5de7d66fb8a3d16e086790bd9 +P ace7e7b64261aeabc9525d5d0cfebe0275c9ddf5 +R 69c353523dfa3ba1b61ddb6b7043eeaf U dan -Z e1e8e8d809370991b491bb9af478a65e +Z b3aef9b0bbf6405eadeabac5f2f1c980 diff --git a/manifest.uuid b/manifest.uuid index 6efb4b3dac..fdbe26a0d1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ace7e7b64261aeabc9525d5d0cfebe0275c9ddf5 \ No newline at end of file +3877c9f50582b51817dcf3cd75d836891a34e590 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 90752033a5..d65c49ed58 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1897,9 +1897,6 @@ static int xferOptimization( if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } - if( HasRowid(pDest)!=HasRowid(pSrc) ){ - return 0; /* source and destination must both be WITHOUT ROWID or not */ - } for(i=0; inCol; i++){ if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){ return 0; /* Affinity must be the same on all columns */ @@ -1958,32 +1955,31 @@ static int xferOptimization( regAutoinc = autoIncBegin(pParse, iDbDest, pDest); regData = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); + sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); + assert( HasRowid(pDest) || destHasUniqueIdx ); + if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ + || destHasUniqueIdx /* (2) */ + || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ + ){ + /* In some circumstances, we are able to run the xfer optimization + ** only if the destination table is initially empty. This code makes + ** that determination. Conditions under which the destination must + ** be empty: + ** + ** (1) There is no INTEGER PRIMARY KEY but there are indices. + ** (If the destination is not initially empty, the rowid fields + ** of index entries might need to change.) + ** + ** (2) The destination has a unique index. (The xfer optimization + ** is unable to test uniqueness.) + ** + ** (3) onError is something other than OE_Abort and OE_Rollback. + */ + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); + emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); + sqlite3VdbeJumpHere(v, addr1); + } if( HasRowid(pSrc) ){ - sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); - if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ - || destHasUniqueIdx /* (2) */ - || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ - ){ - /* In some circumstances, we are able to run the xfer optimization - ** only if the destination table is initially empty. This code makes - ** that determination. Conditions under which the destination must - ** be empty: - ** - ** (1) There is no INTEGER PRIMARY KEY but there are indices. - ** (If the destination is not initially empty, the rowid fields - ** of index entries might need to change.) - ** - ** (2) The destination has a unique index. (The xfer optimization - ** is unable to test uniqueness.) - ** - ** (3) onError is something other than OE_Abort and OE_Rollback. - */ - addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); - emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); - sqlite3VdbeJumpHere(v, addr1); - }else{ - emptyDestTest = 0; - } sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); if( pDest->iPKey>=0 ){ diff --git a/test/tester.tcl b/test/tester.tcl index 3b65127084..27aa08dbe1 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -1028,14 +1028,15 @@ proc explain_i {sql {db db}} { puts "addr opcode p1 p2 p3 p4 p5 #" puts "---- ------------ ------ ------ ------ ---------------- -- -" - set addrTail 0 + set bSeenGoto 0 $db eval "explain $sql" {} { set x($addr) 0 set op($addr) $opcode - if {$opcode == "Goto" && $addrTail==0} { - set addrTail $p2 + if {$opcode == "Goto" && ($bSeenGoto==0 || ($p2 > $addr+10))} { + set linebreak($p2) 1 + set bSeenGoto 1 } if {$opcode == "Next"} { @@ -1049,20 +1050,20 @@ proc explain_i {sql {db db}} { incr x($i) 2 } } + + if {$opcode == "Halt" && $comment == "End of coroutine"} { + set linebreak([expr $addr+1]) 1 + } } $db eval "explain $sql" {} { - if {$addr == $addrTail} { + if {[info exists linebreak($addr)]} { puts "" } set I [string repeat " " $x($addr)] puts [format {%-4d %s%-12.12s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $opcode $p1 $p2 $p3 $p4 $p5 $comment ] - - if {$opcode == "Halt" && $comment == "End of coroutine"} { - puts "" - } } puts "---- ------------ ------ ------ ------ ---------------- -- -" } diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 5a50941857..1da8c3c3d6 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -153,6 +153,55 @@ do_execsql_test 2.4.2 { SELECT * FROM t6 ORDER BY c; } {ABC def ghi ABC def ghi} +#------------------------------------------------------------------------- +# Unless the destination table is completely empty, the xfer optimization +# is disabled for WITHOUT ROWID tables. The following tests check for +# some problems that might occur if this were not the case. +# +reset_db +do_execsql_test 3.1.1 { + CREATE TABLE t1(a, b, PRIMARY KEY(a)) WITHOUT ROWID; + CREATE UNIQUE INDEX i1 ON t1(b); + + CREATE TABLE t2(a, b, PRIMARY KEY(a)) WITHOUT ROWID; + CREATE UNIQUE INDEX i2 ON t2(b); + + INSERT INTO t1 VALUES('one', 'two'); + INSERT INTO t2 VALUES('three', 'two'); +} + +do_execsql_test 3.1.2 { + INSERT OR REPLACE INTO t1 SELECT * FROM t2; + SELECT * FROM t1; +} {three two} + +do_execsql_test 3.1.3 { + DELETE FROM t1; + INSERT INTO t1 SELECT * FROM t2; + SELECT * FROM t1; +} {three two} + +do_catchsql_test 3.1.4 { + INSERT INTO t2 VALUES('four', 'four'); + INSERT INTO t2 VALUES('six', 'two'); + INSERT INTO t1 SELECT * FROM t2; +} {1 {UNIQUE constraint failed: t2.b}} + +do_execsql_test 3.1.5 { + CREATE TABLE t3(a PRIMARY KEY); + CREATE TABLE t4(a PRIMARY KEY); + + INSERT INTO t4 VALUES('i'); + INSERT INTO t4 VALUES('ii'); + INSERT INTO t4 VALUES('iii'); + + INSERT INTO t3 SELECT * FROM t4; + SELECT * FROM t3; +} {i ii iii} + + explain_i { + INSERT INTO t3 SELECT * FROM t4; + } finish_test