From 7465787b97a0a09841e343630a07ba80f1399e4a Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 1 May 2020 18:43:49 +0000 Subject: [PATCH] Fix problems with UPDATE...FROM statements that modify rowid or primary-key values. FossilOrigin-Name: 623ab585d1aa1bdde2df17f1936aa4eec2d997b274acc5c7b291d9566a9ec2c5 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/update.c | 22 ++++++++++++---------- test/upfrom2.test | 31 +++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index abb28b2640..7e5a049d97 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sOOM\stests\sfor\sthe\snew\scode\son\sthis\sbranch. -D 2020-04-30T18:28:40.716 +C Fix\sproblems\swith\sUPDATE...FROM\sstatements\sthat\smodify\srowid\sor\sprimary-key\svalues. +D 2020-05-01T18:43:49.018 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -599,7 +599,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c eee7bae3ec0bc4abee951554bf46a8ba567c0f7752ac90c820ed8afff4c612dc F src/treeview.c 82c6391a3ba76215d4185fd4719a56ec4caf186a40c8a7b6e6ba4ae4467c2742 F src/trigger.c 4ada1037cc99777f647a882cdacbd1a4deb6567b69daf02946286401b88cdc04 -F src/update.c 2f63f9e13c34e4f9fc238e769d8879697d905e542d2e6f9a7a68ea1a5289c631 +F src/update.c 9777ad958b979488ed2e04a7d226048179078916e32437bd633eb4cae191f1a9 F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c 95fb6e03a5ca679045c5adccd05380f0addccabef5911abddcb06af069500ab7 F src/util.c 3b6cedf7a0c69bd6e1acce832873952d416212d6293b18d03064e07d7a9b5118 @@ -1618,7 +1618,7 @@ F test/update.test e906ca7cb1dc6f52af1ea243e08f727edfa79f924c2691f2f9e72481f8473 F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3 F test/upfrom1.tcl 62efddee869b3a6f3e076b2816793fec9422e38d10ea42b63da733cdd2b1ad8e F test/upfrom1.test 543389b4eef43c7a21079df018cf95e29d7c2a4efd09b2597e54a03bbdbd30b9 -F test/upfrom2.test 1dded7ed03e8b335b7ac38f9d70b60380df9049ea13076832ab86fd5b78b4926 +F test/upfrom2.test 79f2d3e4df214010011afdd588ce35410ea1416e0f87aadb48618864347f90a5 F test/upfromfault.test 1e68cc570695a0f8cd16ce09c14210fc43928c7b47b3eda38a99abb0b80c9a65 F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18 F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09 @@ -1866,7 +1866,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 ffcdb6689123bb871c9bd8f977197f86f37c42e9094e2d4bb187ff479f74cf65 -R 9834e1157ceceff37925bd1917b38659 +P e4a18601e5093896e5b323c21aec986b07259353d2ef9455d0a81c6846f40282 +R 31d44a5c5eab4f547b6c4029493d0d87 U dan -Z 98f1c8c70109f9d7189dd668536b4270 +Z 8413be68bb1b4ef61cb95011e58e4ac0 diff --git a/manifest.uuid b/manifest.uuid index f197462623..68d268c748 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e4a18601e5093896e5b323c21aec986b07259353d2ef9455d0a81c6846f40282 \ No newline at end of file +623ab585d1aa1bdde2df17f1936aa4eec2d997b274acc5c7b291d9566a9ec2c5 \ No newline at end of file diff --git a/src/update.c b/src/update.c index 0b98e70174..7aa9fee51d 100644 --- a/src/update.c +++ b/src/update.c @@ -285,6 +285,7 @@ void sqlite3Update( u8 chngRowid; /* Rowid changed in a normal table */ u8 chngKey; /* Either chngPk or chngRowid */ Expr *pRowidExpr = 0; /* Expression defining the new record number */ + int iRowidExpr = -1; AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ @@ -430,6 +431,7 @@ void sqlite3Update( if( j==pTab->iPKey ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ chngPk = 1; } @@ -452,6 +454,7 @@ void sqlite3Update( j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName); pParse->checkSchema = 1; @@ -649,6 +652,8 @@ void sqlite3Update( if( nChangeFrom ){ sqlite3MultiWrite(pParse); eOnePass = ONEPASS_OFF; + nKey = nPk; + regKey = iPk; }else{ if( pUpsert ){ /* If this is an UPSERT, then all cursors have already been opened by @@ -810,7 +815,12 @@ void sqlite3Update( ** already populated. */ assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid ); if( chngRowid ){ - sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); + assert( iRowidExpr>=0 ); + if( nChangeFrom==0 ){ + sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid); + } sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); } @@ -909,15 +919,7 @@ void sqlite3Update( ** documentation. */ if( pPk ){ - int p3, p4; - if( nChangeFrom ){ - p3 = iPk; - p4 = nPk; - }else{ - p3 = regKey; - p4 = nKey; - } - sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, p3, p4); + sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); VdbeCoverage(v); }else{ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); diff --git a/test/upfrom2.test b/test/upfrom2.test index e9bf5eb504..c5df7116e2 100644 --- a/test/upfrom2.test +++ b/test/upfrom2.test @@ -315,5 +315,36 @@ do_execsql_test 3.1 { UPDATE t1 SET z=v FROM input WHERE x=k; } +foreach {tn sql} { + 2 { + CREATE TABLE x1(a INT PRIMARY KEY, b, c) WITHOUT ROWID; + } + 1 { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c); + } + 3 { + CREATE TABLE x1(a INT PRIMARY KEY, b, c); + } +} { + + reset_db + execsql $sql + + do_execsql_test 4.$tn.0 { + INSERT INTO x1 VALUES(1, 1, 1); + INSERT INTO x1 VALUES(2, 2, 2); + INSERT INTO x1 VALUES(3, 3, 3); + INSERT INTO x1 VALUES(4, 4, 4); + INSERT INTO x1 VALUES(5, 5, 5); + CREATE TABLE map(o, t); + INSERT INTO map VALUES(3, 30), (4, 40), (1, 10); + } + + do_execsql_test 4.$tn.1 { + UPDATE x1 SET a=t FROM map WHERE a=o; + SELECT * FROM x1 ORDER BY a; + } {2 2 2 5 5 5 10 1 1 30 3 3 40 4 4} +} + finish_test -- 2.47.2