]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix resolution of unqualified "rowid" identifiers in queries with nested joins.
authordan <Dan Kennedy>
Fri, 15 Sep 2023 20:57:05 +0000 (20:57 +0000)
committerdan <Dan Kennedy>
Fri, 15 Sep 2023 20:57:05 +0000 (20:57 +0000)
FossilOrigin-Name: bbcbd3d537d6790373d97f59386b8ce7fa2177db572af0f1babe058a76e25cc3

manifest
manifest.uuid
src/resolve.c
src/sqliteInt.h
test/joinH.test

index d0c2ef50178c7d5ba7ae3f979a64011ef759e067..b2ddfc0821cbb79355d6395a2c3367370ecfd3be 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Allow\sexpressions\slike\s"<tbl>.rowid"\sto\srefer\sto\simplicit\srowid\scolumns\sof\stables\sin\snested\sFROM\sclauses.
-D 2023-09-15T18:36:51.501
+C Fix\sresolution\sof\sunqualified\s"rowid"\sidentifiers\sin\squeries\swith\snested\sjoins.
+D 2023-09-15T20:57:05.776
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -708,14 +708,14 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
 F src/prepare.c 80548297dc0e1fb3139cdebffb5a1bcac3dfac66d791012dd74838e70445072d
 F src/printf.c e3ba080e2f409f9bfcc8d34724e6fc160e9c718dc92d0548f6b71b8b6f860ce2
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resolve.c f31aab54a4bcb1a3e592daa6b657b7d3a725e40bf764a652dc175006ed4eead2
+F src/resolve.c 1cbb3dacd41882dabe07209242d015f100d36cfb685235278b1d4e15711017b7
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c 5e9ff0eb38e5341780a70e3a39ea1d447c237552d1f552416dc605c123bf2acd
 F src/shell.c.in 62708bea44d4e43aa7b1270ed422d1d29e82297924d4e0f223c39336a3f582f8
 F src/sqlite.h.in 931a58d119d5cf87110648f39fa0bb9f1738b0068cb68250d893304a471bd6c0
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
-F src/sqliteInt.h 6cac7a6d674ea44fa867d929786ddec86df9be64c24d59afbf15c7bac671067c
+F src/sqliteInt.h f2d713fac835f32b131d8a334595b0c471ede3796dab527c705d2b03c32d14e9
 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -1290,7 +1290,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2
 F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
 F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
 F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
-F test/joinH.test 44c51631e487a55902b2ed05706cad19c3ecdd86b7e1c7c8aa84457cec564d11
+F test/joinH.test 832a33079ee8fba7e33fa5ac77c481b3fd8399ba16362d4524a0be22a060b9f2
 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
@@ -2121,11 +2121,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P ce339046416e9ddeffe77f71a8bfb8c5b302160c3207f919aebd62902618ed59
-R bcfd521e8d34de98592bf4e489ebb783
-T *branch * nested-from-rowid-expansion
-T *sym-nested-from-rowid-expansion *
-T -sym-trunk *
+P 59a1bbc69f5dbb33418fa4b383393fb13a46bc1e531577da8ad54ae2fad5a10e
+R 790b7202228cf2f5b7a7a80533c697dd
 U dan
-Z dee6d86baf948e05aa8b2bb5ee3449dc
+Z ce4b0349e1c5a42e7e7210175df9fc25
 # Remove this line to create a well-formed Fossil manifest.
index eec8fc8c4080ee8ccd41a2257c3b65723eece622..2c2a02ac67401209fe20c0c77da4cb3ee7425ab3 100644 (file)
@@ -1 +1 @@
-59a1bbc69f5dbb33418fa4b383393fb13a46bc1e531577da8ad54ae2fad5a10e
\ No newline at end of file
+bbcbd3d537d6790373d97f59386b8ce7fa2177db572af0f1babe058a76e25cc3
\ No newline at end of file
index 20bce29a2140c3232dd24ef68b875f3f9a2feb61..6935480cedcb6e9b35e6f3a3adc20db8a835affb 100644 (file)
@@ -117,22 +117,23 @@ static void resolveAlias(
 ** SF_NestedFrom subqueries also store an entry for the implicit rowid (or
 ** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID,
 ** and setting zSpan to "DATABASE.TABLE.<rowid-alias>". This type of pItem
-** argument matches if bRowidOk is true, zTab is not NULL, zCol is a rowid
-** alias, and zDb matches as for the usual case.
+** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid)
+** is set to 1 if there is this kind of match.
 */
 int sqlite3MatchEName(
   const struct ExprList_item *pItem,
   const char *zCol,
   const char *zTab,
   const char *zDb,
-  int bRowidOk
+  int *pbRowid
 ){
   int n;
   const char *zSpan;
   int eEName = pItem->fg.eEName;
-  if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || bRowidOk==0 || zTab==0) ){
+  if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || pbRowid==0) ){
     return 0;
   }
+  assert( pbRowid==0 || *pbRowid==0 );
   zSpan = pItem->zEName;
   for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
   if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
@@ -148,6 +149,7 @@ int sqlite3MatchEName(
     if( eEName==ENAME_TAB && sqlite3StrICmp(zSpan, zCol)!=0 ) return 0;
     if( eEName==ENAME_ROWID && sqlite3IsRowid(zCol)==0 ) return 0;
   }
+  if( eEName==ENAME_ROWID ) *pbRowid = 1;
   return 1;
 }
 
@@ -357,39 +359,44 @@ static int lookupName(
           assert( pEList!=0 );
           assert( pEList->nExpr==pTab->nCol );
           for(j=0; j<pEList->nExpr; j++){
-            if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, cnt==0) ){
+            int bRowid = 0;       /* True if possible rowid match */
+            if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
               continue;
             }
-            if( cnt>0 ){
-              if( pItem->fg.isUsing==0
-               || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
-              ){
-                /* Two or more tables have the same column name which is
-                ** not joined by USING.  This is an error.  Signal as much
-                ** by clearing pFJMatch and letting cnt go above 1. */
-                sqlite3ExprListDelete(db, pFJMatch);
-                pFJMatch = 0;
-              }else
-              if( (pItem->fg.jointype & JT_RIGHT)==0 ){
-                /* An INNER or LEFT JOIN.  Use the left-most table */
-                continue;
-              }else
-              if( (pItem->fg.jointype & JT_LEFT)==0 ){
-                /* A RIGHT JOIN.  Use the right-most table */
-                cnt = 0;
-                sqlite3ExprListDelete(db, pFJMatch);
-                pFJMatch = 0;
-              }else{
-                /* For a FULL JOIN, we must construct a coalesce() func */
-                extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+            if( bRowid==0 ){
+              if( cnt>0 ){
+                if( pItem->fg.isUsing==0
+                 || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+                ){
+                  /* Two or more tables have the same column name which is
+                  ** not joined by USING.  This is an error.  Signal as much
+                  ** by clearing pFJMatch and letting cnt go above 1. */
+                  sqlite3ExprListDelete(db, pFJMatch);
+                  pFJMatch = 0;
+                }else
+                if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+                  /* An INNER or LEFT JOIN.  Use the left-most table */
+                  continue;
+                }else
+                if( (pItem->fg.jointype & JT_LEFT)==0 ){
+                  /* A RIGHT JOIN.  Use the right-most table */
+                  cnt = 0;
+                  sqlite3ExprListDelete(db, pFJMatch);
+                  pFJMatch = 0;
+                }else{
+                  /* For a FULL JOIN, we must construct a coalesce() func */
+                  extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+                }
               }
+              cnt++;
+              hit = 1;
+            }else if( cnt>0 ){
+              continue;
             }
-            cnt++;
-            cntTab = 2;
+            cntTab++;
             pMatch = pItem;
             pExpr->iColumn = j;
             pEList->a[j].fg.bUsed = 1;
-            hit = 1;
             if( pEList->a[j].fg.bUsingTerm ) break;
           }
           if( hit || zTab==0 ) continue;
@@ -584,10 +591,10 @@ static int lookupName(
      && pMatch
      && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
      && sqlite3IsRowid(zCol)
-     && ALWAYS(VisibleRowid(pMatch->pTab))
+     && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
     ){
       cnt = 1;
-      pExpr->iColumn = -1;
+      if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
       pExpr->affExpr = SQLITE_AFF_INTEGER;
     }
 
index b8473b2d1dd99e8bdaad4b01e2b3705b259b5d49..225e54800ba1a5b05bf57907d544fddd27cbcc10 100644 (file)
@@ -5284,7 +5284,7 @@ int sqlite3MatchEName(
   const char*,
   const char*,
   const char*,
-  int
+  int*
 );
 Bitmask sqlite3ExprColUsed(Expr*);
 u8 sqlite3StrIHash(const char*);
index 3c1a55e8e8634ec1d0fa5a1e619e9e8deb5af89f..1e1d322a28fd83c97a1de022e82b0afa18fedbad 100644 (file)
@@ -176,6 +176,7 @@ do_execsql_test 8.1 {
   SELECT x3.oid FROM x1 JOIN (x2 JOIN x3 ON c='c')
 } 43
 
+breakpoint
 do_execsql_test 8.2 {
   SELECT x3.rowid FROM x1 JOIN (x2 JOIN x3 ON c='c')
 } {hello}
@@ -195,18 +196,31 @@ do_execsql_test 9.0 {
 
   CREATE TABLE wo1(a PRIMARY KEY, b) WITHOUT ROWID;
   CREATE TABLE wo2(a PRIMARY KEY, rowid) WITHOUT ROWID;
+  CREATE TABLE wo3(a PRIMARY KEY, b) WITHOUT ROWID;
 }
 
-# Should an error.
 do_catchsql_test 9.1 {
-  SELECT rowid FROM wo1 JOIN (x1 JOIN x2);
+  SELECT rowid FROM wo1, x1, x2;
 } {1 {no such column: rowid}}
-
-# Should not be an error.
 do_catchsql_test 9.2 {
+  SELECT rowid FROM wo1, (x1, x2);
+} {1 {no such column: rowid}}
+do_catchsql_test 9.3 {
+  SELECT rowid FROM wo1 JOIN (x1 JOIN x2);
+} {1 {no such column: rowid}}
+do_catchsql_test 9.4 {
+  SELECT a FROM wo1, x1, x2;
+} {1 {ambiguous column name: a}}
+do_catchsql_test 9.5 {
   SELECT rowid FROM x1 JOIN (x2 JOIN wo2);
 } {0 {}}
 
+do_catchsql_test 9.6 {
+  SELECT _rowid_ FROM wo1 JOIN (wo3 JOIN x3)
+} {0 {}}
+
+
+
 
 finish_test