]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Now supports result sets of the form "TABLE.*" with nested FROM clauses.
authordrh <drh@noemail.net>
Thu, 3 Jan 2013 00:45:56 +0000 (00:45 +0000)
committerdrh <drh@noemail.net>
Thu, 3 Jan 2013 00:45:56 +0000 (00:45 +0000)
FossilOrigin-Name: 4cf5ed7ea198abc32f8118e79490e77f847f08c1

manifest
manifest.uuid
src/expr.c
src/resolve.c
src/select.c
src/sqliteInt.h
test/selectD.test

index 4270211ad5be66fd37d977fdc3c9f6b60dbd6872..6f14f4982c587785e2de4b6585fa7059853bf931 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C When\sresolving\sresult-set\sname\scollisions,\smake\sthem\sx:1,\sx:2,\sx:3,\setc.\ninstead\sof\sx:1,\sx:1:1,\sx:1;1;1.
-D 2013-01-02T14:57:32.750
+C Now\ssupports\sresult\ssets\sof\sthe\sform\s"TABLE.*"\swith\snested\sFROM\sclauses.
+D 2013-01-03T00:45:56.842
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -130,7 +130,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e
 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
 F src/delete.c 9b8d308979114991e5dc7cee958316e07186941d
-F src/expr.c 0e41d66d868b37dbc0e041c342e0036fad27e705
+F src/expr.c 4dff0b04eaaf133789279c6b8cd69175dfbb1691
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 5b7a12e2f8620e855b0478a9a6798df9967bb277
 F src/func.c 8147799b048065a1590805be464d05b4913e652c
@@ -172,14 +172,14 @@ F src/pragma.c 8907c559d3127729d3bcedb1fe5c59fc196d3a17
 F src/prepare.c 931ad0d852a0df48f79adcba6ce79ca5f475625c
 F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
-F src/resolve.c 3104a5e4c2cb6e3a813b7266cbd541dc91e26fad
+F src/resolve.c e00f17ac321b48f022e0154e5c2fb90456b6d3a6
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
-F src/select.c bdede5fc109ab090dd6ce5edf6090434dc41bc0e
+F src/select.c 9a76144e137fbe26bad3c5ef06e0acd953de9f59
 F src/shell.c 11c9611580bb2ffce3a232f31f7f8cc310df0843
 F src/sqlite.h.in 39cc33bb08897c748fe3383c29ccf56585704177
 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
-F src/sqliteInt.h 2ce2d742e32be86bf1fc8e29c91ef91c29c32e60
+F src/sqliteInt.h e998703742455b2241731424c6ec142fd8d0258f
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -701,7 +701,7 @@ F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea
 F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
-F test/selectD.test 243db87cd12f62aca4fe3f8b9465dfeab30b4d7a
+F test/selectD.test 5e05091a755b12e0afd350137c49b25f7d9bc61b
 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
 F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
 F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
@@ -1031,7 +1031,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P a5f4d2b641f7fafb6f1a312efeffb10f213d2d0a
-R c34797fdba8f90f34f8f47a91737b456
+P ef01e30456670e6b1bc67fe41ec27e52c182efaf
+R 0fd360c4969bf18ffc741f29481411d6
 U drh
-Z 110af146cb022182bd89fc0a02fd1d9b
+Z a4217b32c27253cef4a6339df637b923
index 24c1cff51c305baeac8a8c5a801e114d5488145e..1c88f392e4c4aeeb8adee7b8e3d8cb9a94d535cf 100644 (file)
@@ -1 +1 @@
-ef01e30456670e6b1bc67fe41ec27e52c182efaf
\ No newline at end of file
+4cf5ed7ea198abc32f8118e79490e77f847f08c1
\ No newline at end of file
index 9ca34ec7b7f79a4592c32f8a0182093b39059a81..5ba26169195556cb9e402549fe80db15cb173797 100644 (file)
@@ -3281,6 +3281,12 @@ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
       sqlite3ExplainPush(pOut);
       sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
       sqlite3ExplainPop(pOut);
+      if( pList->a[i].zName ){
+        sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
+      }
+      if( pList->a[i].bSpanIsTab ){
+        sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
+      }
       if( i<pList->nExpr-1 ){
         sqlite3ExplainNL(pOut);
       }
index 317ca3d81b06d93370e61564ac41c6dd852423e6..e1bcbcc5c1cf33adf25389893a67c8a2970516f7 100644 (file)
@@ -150,6 +150,35 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
   return 0;
 }
 
+/*
+** Subqueries stores the original database, table and column names for their
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
+** Check to see if the zSpan given to this routine matches the zDb, zTab,
+** and zCol.  If any of zDb, zTab, and zCol are NULL then those fields will
+** match anything.
+*/
+int sqlite3MatchSpanName(
+  const char *zSpan,
+  const char *zCol,
+  const char *zTab,
+  const char *zDb
+){
+  int n;
+  for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
+  if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
+    return 0;
+  }
+  zSpan += n+1;
+  for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
+  if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
+    return 0;
+  }
+  zSpan += n+1;
+  if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
+    return 0;
+  }
+  return 1;
+}
 
 /*
 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
@@ -240,8 +269,7 @@ static int lookupName(
           ExprList *pEList = pItem->pSelect->pEList;
           int hit = 0;
           for(j=0; j<pEList->nExpr; j++){
-            if( zTab && sqlite3StrICmp(pEList->a[j].zSpan, zTab)!=0 ) continue;
-            if( sqlite3StrICmp(pEList->a[j].zName, zCol)==0 ){
+            if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
               cnt++;
               cntTab = 2;
               pMatch = pItem;
index 7c7974e256de6c72fcc76a08122c72dc36c6906c..502c524fd6a98442c9d31f8382d339cc71a6632c 100644 (file)
@@ -3294,6 +3294,7 @@ static int selectExpander(Walker *pWalker, Select *p){
   ExprList *pEList;
   struct SrcList_item *pFrom;
   sqlite3 *db = pParse->db;
+  Expr *pE, *pRight, *pExpr;
 
   if( db->mallocFailed  ){
     return WRC_Abort;
@@ -3379,7 +3380,7 @@ static int selectExpander(Walker *pWalker, Select *p){
   ** that need expanding.
   */
   for(k=0; k<pEList->nExpr; k++){
-    Expr *pE = pEList->a[k].pExpr;
+    pE = pEList->a[k].pExpr;
     if( pE->op==TK_ALL ) break;
     assert( pE->op!=TK_DOT || pE->pRight!=0 );
     assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
@@ -3399,9 +3400,10 @@ static int selectExpander(Walker *pWalker, Select *p){
                       && (p->selFlags & SF_NestedFrom)==0;
 
     for(k=0; k<pEList->nExpr; k++){
-      Expr *pE = a[k].pExpr;
-      assert( pE->op!=TK_DOT || pE->pRight!=0 );
-      if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
+      pE = a[k].pExpr;
+      pRight = pE->pRight;
+      assert( pE->op!=TK_DOT || pRight!=0 );
+      if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
         /* This particular expression does not need to be expanded.
         */
         pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
@@ -3416,32 +3418,42 @@ static int selectExpander(Walker *pWalker, Select *p){
         /* This expression is a "*" or a "TABLE.*" and needs to be
         ** expanded. */
         int tableSeen = 0;      /* Set to 1 when TABLE matches */
-        char *zTName;            /* text of name of TABLE */
+        char *zTName = 0;       /* text of name of TABLE */
         if( pE->op==TK_DOT ){
           assert( pE->pLeft!=0 );
           assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
           zTName = pE->pLeft->u.zToken;
-        }else{
-          zTName = 0;
         }
         for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
           Table *pTab = pFrom->pTab;
+          Select *pSub = pFrom->pSelect;
           char *zTabName = pFrom->zAlias;
+          const char *zSchemaName = 0;
           if( zTabName==0 ){
             zTabName = pTab->zName;
           }
           if( db->mallocFailed ) break;
-          if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
-            continue;
+          if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
+            int iDb;
+            pSub = 0;
+            if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
+              continue;
+            }
+            iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+            zSchemaName = iDb>=0 ? db->aDb[i].zName : "*";
           }
-          tableSeen = 1;
           for(j=0; j<pTab->nCol; j++){
-            Expr *pExpr, *pRight;
             char *zName = pTab->aCol[j].zName;
             char *zColname;  /* The computed column name */
             char *zToFree;   /* Malloced string that needs to be freed */
             Token sColname;  /* Computed column name as a token */
 
+            if( zTName && pSub
+             && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
+            ){
+              continue;
+            }
+
             /* If a column is marked as 'hidden' (currently only possible
             ** for virtual tables), do not include it in the expanded
             ** result-set list.
@@ -3450,6 +3462,7 @@ static int selectExpander(Walker *pWalker, Select *p){
               assert(IsVirtual(pTab));
               continue;
             }
+            tableSeen = 1;
 
             if( i>0 && zTName==0 ){
               if( (pFrom->jointype & JT_NATURAL)!=0
@@ -3484,7 +3497,14 @@ static int selectExpander(Walker *pWalker, Select *p){
             sColname.n = sqlite3Strlen30(zColname);
             sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
             if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
-              pNew->a[pNew->nExpr-1].zSpan = sqlite3DbStrDup(db, zTabName);
+              struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
+              if( pSub ){
+                pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
+              }else{
+                pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
+                                           zSchemaName, zTabName, zColname);
+              }
+              pX->bSpanIsTab = 1;
             }
             sqlite3DbFree(db, zToFree);
           }
index 2a28594fe597cda3edea4e9a652252527c790ff8..74fa0b31caa0690c4a93fc3ba5e59355d21cf99b 100644 (file)
@@ -1777,7 +1777,8 @@ struct Expr {
 ** column labels.  In this case, Expr.zSpan is typically the text of a
 ** column expression as it exists in a SELECT statement.  However, if
 ** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
-** of the table to which the column of a FROM-clause subquery refers.
+** of the result column in the form: DATABASE.TABLE.COLUMN.  This later
+** form is used for name resolution with nested FROM clauses.
 */
 struct ExprList {
   int nExpr;             /* Number of expressions on the list */
@@ -1788,7 +1789,7 @@ struct ExprList {
     char *zSpan;            /* Original text of the expression */
     u8 sortOrder;           /* 1 for DESC or 0 for ASC */
     unsigned done :1;       /* A flag to indicate when processing is finished */
-    unsigned bSpanIsTab :1; /* zSpan holds table name, not the span */
+    unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
     u16 iOrderByCol;        /* For ORDER BY, column number in result set */
     u16 iAlias;             /* Index into Parse.aAlias[] for zName */
   } *a;                  /* Alloc a power of two greater or equal to nExpr */
@@ -3080,6 +3081,7 @@ void sqlite3NestedParse(Parse*, const char*, ...);
 void sqlite3ExpirePreparedStatements(sqlite3*);
 int sqlite3CodeSubselect(Parse *, Expr *, int, int);
 void sqlite3SelectPrep(Parse*, Select*, NameContext*);
+int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
 int sqlite3ResolveExprNames(NameContext*, Expr*);
 void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
 int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
index 8c862264347f5d2af8d8ccab0e4a89084675613f..6c01b2d5cb3ae841aa3e2665d293bbe0dc479067 100644 (file)
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-do_test selectD-1.1 {
-  db eval {
-    CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(111,'x1');
-    CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(222,'x2');
-    CREATE TABLE t3(a,b); INSERT INTO t3 VALUES(333,'x3');
-    CREATE TABLE t4(a,b); INSERT INTO t4 VALUES(444,'x4');
 
-    SELECT *
-      FROM (t1), (t2), (t3), (t4)
-     WHERE t4.a=t3.a+111 
-       AND t3.a=t2.a+111
-       AND t2.a=t1.a+111;
+for {set i 1} {$i<=2} {incr i} {
+  db close
+  forcedelete test$i.db
+  sqlite3 db test$i.db
+  if {$i==2} {
+    optimization_control db query-flattener off
   }
-} {111 x1 222 x2 333 x3 444 x4}
-do_test selectD-1.2 {
-  db eval {
-    SELECT *
-      FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
-                            ON t3.a=t2.a+111)
-                   ON t2.a=t1.a+111;
-  }
-} {111 x1 222 x2 333 x3 444 x4}
-do_test selectD-1.3 {
-  db eval {
-    UPDATE t2 SET a=111;
-    UPDATE t3 SET a=111;
-    UPDATE t4 SET a=111;
-    SELECT *
-      FROM t1 JOIN (t2 JOIN (t3 JOIN t4 USING(a)) USING (a)) USING (a);
-  }
-} {111 x1 x2 x3 x4}
-do_test selectD-1.4 {
-  db eval {
-    UPDATE t2 SET a=111;
-    UPDATE t3 SET a=111;
-    UPDATE t4 SET a=111;
-    SELECT *
-      FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 USING(a))
-                                      USING (a))
-                         USING (a);
-  }
-} {111 x1 x2 x3 x4}
-do_test selectD-1.5 {
-  db eval {
-    UPDATE t3 SET a=222;
-    UPDATE t4 SET a=222;
-    SELECT *
-      FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
-           ON t1.a=t3.a-111;
-  }
-} {111 x1 x2 222 x3 x4}
-do_test selectD-1.6 {
-  db eval {
-    UPDATE t4 SET a=333;
-    SELECT *
-      FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
-           ON t1.a=t3.a-111;
-  }
-} {111 x1 x2 222 x3 {}}
+  do_test selectD-$i.0 {
+    db eval {
+      CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(111,'x1');
+      CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(222,'x2');
+      CREATE TEMP TABLE t3(a,b); INSERT INTO t3 VALUES(333,'x3');
+      CREATE TABLE t4(a,b); INSERT INTO t4 VALUES(444,'x4');
+    }
+  } {}
+  do_test selectD-$i.1 {
+    db eval {
+      SELECT *
+        FROM (t1), (t2), (t3), (t4)
+       WHERE t4.a=t3.a+111 
+         AND t3.a=t2.a+111
+         AND t2.a=t1.a+111;
+    }
+  } {111 x1 222 x2 333 x3 444 x4}
+  do_test selectD-$i.2.1 {
+    db eval {
+      SELECT *
+        FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
+                              ON t3.a=t2.a+111)
+                     ON t2.a=t1.a+111;
+    }
+  } {111 x1 222 x2 333 x3 444 x4}
+  do_test selectD-$i.2.2 {
+    db eval {
+      SELECT t3.a
+        FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
+                              ON t3.a=t2.a+111)
+                     ON t2.a=t1.a+111;
+    }
+  } {333}
+  do_test selectD-$i.2.3 {
+    db eval {
+      SELECT t3.*
+        FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
+                              ON t3.a=t2.a+111)
+                     ON t2.a=t1.a+111;
+    }
+  } {333 x3}
+  do_test selectD-$i.2.3 {
+    db eval {
+      SELECT t3.*, t2.*
+        FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111)
+                              ON t3.a=t2.a+111)
+                     ON t2.a=t1.a+111;
+    }
+  } {333 x3 222 x2}
+  do_test selectD-$i.3 {
+    db eval {
+      UPDATE t2 SET a=111;
+      UPDATE t3 SET a=111;
+      UPDATE t4 SET a=111;
+      SELECT *
+        FROM t1 JOIN (t2 JOIN (t3 JOIN t4 USING(a)) USING (a)) USING (a);
+    }
+  } {111 x1 x2 x3 x4}
+  do_test selectD-$i.4 {
+    db eval {
+      UPDATE t2 SET a=111;
+      UPDATE t3 SET a=111;
+      UPDATE t4 SET a=111;
+      SELECT *
+        FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 USING(a))
+                                        USING (a))
+                           USING (a);
+    }
+  } {111 x1 x2 x3 x4}
+  do_test selectD-$i.5 {
+    db eval {
+      UPDATE t3 SET a=222;
+      UPDATE t4 SET a=222;
+      SELECT *
+        FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
+             ON t1.a=t3.a-111;
+    }
+  } {111 x1 x2 222 x3 x4}
+  do_test selectD-$i.6 {
+    db eval {
+      UPDATE t4 SET a=333;
+      SELECT *
+        FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
+             ON t1.a=t3.a-111;
+    }
+  } {111 x1 x2 222 x3 {}}
+  do_test selectD-$i.7 {
+    db eval {
+      SELECT t1.*, t2.*, t3.*, t4.b
+        FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a))
+             ON t1.a=t3.a-111;
+    }
+  } {111 x1 111 x2 222 x3 {}}
+}
 
 finish_test