From: dan Date: Wed, 15 Jul 2020 18:30:01 +0000 (+0000) Subject: Fix problems that could occur if a table with the same name as the table being update... X-Git-Tag: version-3.33.0~53^2~9^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=576d5a8634851f3762c0ee527511ca53016eab7e;p=thirdparty%2Fsqlite.git Fix problems that could occur if a table with the same name as the table being updated appeared in the FROM clause of an UPDATE statement. FossilOrigin-Name: 13224cbd75990615088f3e30ccba05d31b3099fae4300c9ab8f7663bc5f0eb6f --- diff --git a/manifest b/manifest index 872b6d5db8..e34967af0c 100644 --- a/manifest +++ b/manifest @@ -1,15 +1,15 @@ B 5ee3c27e20d12a126fb773b428bb864102b949a5b26a8d5c523753dcedf4be10 -C Fix\sa\sproblem\sin\sSQLITE_ENABLE_HIDDEN_COLUMN\sbuilds\soccuring\swhen\san\sUPDATE...FROM\sfired\san\sINSTEAD\sOF\strigger. -D 2020-07-15T15:32:59.655 +C Fix\sproblems\sthat\scould\soccur\sif\sa\stable\swith\sthe\ssame\sname\sas\sthe\stable\sbeing\supdated\sappeared\sin\sthe\sFROM\sclause\sof\san\sUPDATE\sstatement. +D 2020-07-15T18:30:01.625 F src/alter.c c63fb72ae0ca39175996fcf7008d44022a7ea99e03c0af3e1d968505ceff7120 F src/attach.c 0b11e00c166b622c84ec176773b1d691c61ad07d247809e3e1635d4e99e71d30 F src/btree.c b8b0e80c8bbe4e1fb35ae559e9e9aa009799c20cf12f159ebb503b05be1fab9b F src/parse.y ecb9abdd79ec86c8dca7cb126bbdcf322c0e282f87a6d0d734ea5f2c57ced516 -F src/resolve.c 04f4710d3ab0070073b60b5b963158dadfbd049db55d10742d9fbd3f28a3f4b8 +F src/resolve.c 2dd6821aac2cd27de9fcf6aa6d1f8c41b4b5841c9bc58bf1c9109008009a3a2e F src/select.c a48570f614f777d02dd7f419789944225432a9231b2dbca863411ac19e5fb683 F src/sqliteInt.h e2684c4ba7ee9c0a0529ae2eb847cc5bf923e4104a9d0944bf3d9d151856b6ab F src/trigger.c 6ff9c64a06e6354df8eba08ae18bc809e79931175d39dda32bf1101adee238e5 -F src/update.c d9b7f86c8d694f5131152b4c216ba257844a8bf63ec4bfe71dbe511cad8a7600 +F src/update.c d254339ce702ca08e4761efcc3b841895f09e6a144f4d2b65f4da9e872f9825d F src/where.c 35cb38d45294118e484fd3a8011aaee8ebe96b28855a6913575a7fe3722d7af5 F test/altertab3.test d0d51e652aaa11e37de1f1215181d88334fefcb185f3b9bd91e06e98260c4694 F test/decimal.test fcf403fd5585f47342234e153c4a4338cd737b8e0884ac66fc484df47dbcf1a7 @@ -18,8 +18,8 @@ F test/fuzzdata8.db 281cbc8166a8bc5843f4a913e803ba76e27905eb02fb9d5cfd581c2429f2 F test/triggerupfrom.test d25961fa70a99b6736193da7b49a36d8c1d28d56188f0be6406d4366315cd6e4 F test/upfrom1.tcl df984cb88010af1555812af55e9db44c4df50677395b45d1f30b69b1b6c07b73 F test/upfrom1.test 2ba1ed45b4a2161fc79f234b9ce4300b0d3deba545e3f23b938fb3ebdbf8758d -F test/upfrom3.test 2619374c4806913414cc39514630d85bb12489a5f09a5ebdf6fad0fb4df242e2 -P 53b8b507a10364f5d580655d89c950a5f14c2a8114625fd8749d77f289413b22 -R 50049e7505da24bcfa1309cf7e88265f +F test/upfrom3.test 3890e1fc372aaf70ca88ec2650f4574b169368a5a63770245a45a28f1524b1b9 +P 5176cb7a6a4e8cfa1973aaae46fcd7d39baedb70ae20bfacc82d62ca39fb0aa3 +R 5994321bbabb2542296f6db00df19961 U dan -Z 6a5f095ea5bbd01f6db55318ec51bead +Z 41a21fcf4a769b492a5346939daeca22 diff --git a/manifest.uuid b/manifest.uuid index b024410586..d68e77393b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5176cb7a6a4e8cfa1973aaae46fcd7d39baedb70ae20bfacc82d62ca39fb0aa3 \ No newline at end of file +13224cbd75990615088f3e30ccba05d31b3099fae4300c9ab8f7663bc5f0eb6f \ No newline at end of file diff --git a/src/resolve.c b/src/resolve.c index 8e06344c7a..3fa3cf97bd 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -766,11 +766,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ struct SrcList_item *pItem; assert( pSrcList && pSrcList->nSrc>=1 ); pItem = pSrcList->a; - assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; - pExpr->iColumn = -1; + pExpr->iColumn--; pExpr->affExpr = SQLITE_AFF_INTEGER; break; } diff --git a/src/update.c b/src/update.c index c321edce8e..9cc0e4f64f 100644 --- a/src/update.c +++ b/src/update.c @@ -131,14 +131,36 @@ static int indexWhereClauseMightChange( } /* -** This function generates VM code to run the query: +** Allocate and return a pointer to an expression of type TK_ROW with +** Expr.iColumn set to value (iCol+1). The resolver will modify the +** expression to be a TK_COLUMN reading column iCol of the first +** table in the source-list (pSrc->a[0]). +*/ +static Expr *exprRowColumn(Parse *pParse, int iCol){ + Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0); + if( pRet ) pRet->iColumn = iCol+1; + return pRet; +} + +/* +** Assuming both the pLimit and pOrderBy parameters are NULL, this function +** generates VM code to run the query: ** -** SELECT , pChanges FROM pTabList WHERE pWhere +** SELECT , pChanges FROM pTabList WHERE pWhere ** ** and write the results to the ephemeral table already opened as cursor ** iEph. None of pChanges, pTabList or pWhere are modified or consumed by ** this function, they must be deleted by the caller. ** +** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view: +** +** SELECT , pChanges FROM pTabList +** WHERE pWhere +** GROUP BY +** ORDER BY pOrderBy LIMIT pLimit +** +** If pTab is a view, the GROUP BY clause is omitted. +** ** Exactly how results are written to table iEph, and exactly what ** the in the query above are is determined by the type ** of table pTabList->a[0].pTab. @@ -158,7 +180,7 @@ static int indexWhereClauseMightChange( ** rowid value in is used as the integer key, and the ** remaining fields make up the table record. */ -static void updatePopulateEphTable( +static void updateFromSelect( Parse *pParse, /* Parse context */ int iEph, /* Cursor for open eph. table */ Index *pPk, /* PK if table 0 is WITHOUT ROWID */ @@ -172,7 +194,7 @@ static void updatePopulateEphTable( SelectDest dest; Select *pSelect = 0; ExprList *pList = 0; - ExprList *pGroupBy = 0; + ExprList *pGrp = 0; sqlite3 *db = pParse->db; Table *pTab = pTabList->a[0].pTab; SrcList *pSrc; @@ -199,34 +221,23 @@ static void updatePopulateEphTable( } if( pPk ){ for(i=0; inKeyCol; i++){ - Expr *pNew = sqlite3PExpr(pParse, TK_DOT, - sqlite3Expr(db, TK_ID, pTab->zName), - sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName) - ); + Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]); if( pLimit ){ - pGroupBy = sqlite3ExprListAppend(pParse, pGroupBy, - sqlite3ExprDup(db, pNew, 0) - ); + pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0)); } pList = sqlite3ExprListAppend(pParse, pList, pNew); } eDest = SRT_Upfrom; }else if( pTab->pSelect ){ - pList = sqlite3ExprListAppend(pParse, pList, - sqlite3PExpr(pParse, TK_DOT, - sqlite3Expr(db, TK_ID, pTab->zName), - sqlite3PExpr(pParse, TK_ASTERISK, 0, 0) - )); + for(i=0; inCol; i++){ + pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); + } eDest = SRT_Table; }else{ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; - pList = sqlite3ExprListAppend(pParse, pList, - sqlite3PExpr(pParse, TK_ROW, 0, 0) - ); + pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); if( pLimit ){ - pGroupBy = sqlite3ExprListAppend(pParse, pGroupBy, - sqlite3PExpr(pParse, TK_ROW, 0, 0) - ); + pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); } } assert( pChanges || db->mallocFailed ); @@ -238,7 +249,7 @@ static void updatePopulateEphTable( } } pSelect = sqlite3SelectNew(pParse, pList, - pSrc, pWhere2, pGroupBy, 0, pOrderBy2, SF_IncludeHidden, pLimit2 + pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_IncludeHidden, pLimit2 ); sqlite3SelectDestInit(&dest, eDest, iEph); dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); @@ -652,7 +663,7 @@ void sqlite3Update( } } if( nChangeFrom ){ - updatePopulateEphTable( + updateFromSelect( pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit ); #ifndef SQLITE_OMIT_SUBQUERY @@ -1169,31 +1180,26 @@ static void updateVirtualTable( regArg = pParse->nMem + 1; pParse->nMem += nArg; if( pSrc->nSrc>1 ){ - ExprList *pList = 0; + Expr *pRow; + ExprList *pList; if( pRowid ){ - pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db,pRowid,0)); + pRow = sqlite3ExprDup(db, pRowid, 0); }else{ - pList = sqlite3ExprListAppend(pParse, pList, - sqlite3PExpr(pParse, TK_DOT, - sqlite3Expr(db, TK_ID, pTab->zName), - sqlite3Expr(db, TK_ID, "_rowid_") - )); + pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0); } + pList = sqlite3ExprListAppend(pParse, 0, pRow); + for(i=0; inCol; i++){ if( aXRef[i]>=0 ){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0) ); }else{ - pList = sqlite3ExprListAppend(pParse, pList, - sqlite3PExpr(pParse, TK_DOT, - sqlite3Expr(db, TK_ID, pTab->zName), - sqlite3Expr(db, TK_ID, pTab->aCol[i].zName) - )); + pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); } } - updatePopulateEphTable(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0); + updateFromSelect(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0); sqlite3ExprListDelete(db, pList); eOnePass = ONEPASS_OFF; }else{ diff --git a/test/upfrom3.test b/test/upfrom3.test index cd1e8c6852..d191cfe3fe 100644 --- a/test/upfrom3.test +++ b/test/upfrom3.test @@ -22,6 +22,9 @@ set testprefix upfrom3 # 2.*: Test UPDATE ... FROM statements that modify PK fields of WITHOUT # ROWID tables. # +# 3.*: Test that UPDATE ... FROM statements are not confused if there +# are multiple tables of the same name in attached databases. +# foreach {tn wo} { 1 "" @@ -171,5 +174,40 @@ do_execsql_test 2.1.4 { 3 60 60 } +#------------------------------------------------------------------------- +foreach {tn wo} { + 1 "" + 2 "WITHOUT ROWID" +} { + reset_db + forcedelete test.db2 + eval [string map [list %WO% $wo %TN% $tn] { + do_execsql_test 3.$tn.1 { + CREATE TABLE g1(a, b, c, PRIMARY KEY(a, b)) %WO%; + INSERT INTO g1 VALUES(1, 1, 1); + + ATTACH 'test.db2' AS aux; + CREATE TABLE aux.g1(a, b, c, PRIMARY KEY(a, b)) %WO%; + INSERT INTO aux.g1 VALUES(10, 1, 10); + INSERT INTO aux.g1 VALUES(20, 2, 20); + INSERT INTO aux.g1 VALUES(30, 3, 30); + } + + do_execsql_test 3.$tn.2 { + UPDATE aux.g1 SET c=101 FROM main.g1; + } + do_execsql_test 3.$tn.3 { + SELECT * FROM aux.g1; + } {10 1 101 20 2 101 30 3 101} + + do_execsql_test 3.$tn.4 { + UPDATE g1 SET c=101 FROM g1; + } + do_execsql_test 3.$tn.5 { + SELECT * FROM g1; + } {1 1 101} + }] +} + finish_test