]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
ORDER BY in a compound SELECT will first match against the left-most SELECT.
authordrh <drh@noemail.net>
Thu, 13 Dec 2007 03:45:07 +0000 (03:45 +0000)
committerdrh <drh@noemail.net>
Thu, 13 Dec 2007 03:45:07 +0000 (03:45 +0000)
If there is no match there, it begins working its way to the right. (CVS 4621)

FossilOrigin-Name: 56063ec84b130bcdb0e90bc76fabca394d0d867f

manifest
manifest.uuid
src/select.c
src/sqliteInt.h
test/null.test
test/select4.test

index 155b9f9da31a0f50de7b0f306cc7e7ad316ad7cd..d0f482bc580ba9fc882847d1c14fbd16aff8a096 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Towards\sgetting\sORDER\sBY\sto\smatch\sagainst\sthe\scorrectin\scolumns.\nThis\sversion\sonly\slooks\sat\sthe\sleft-most\scolumn\sin\sa\scompound\sSELECT.\nThat\sis\sthe\scorrect\sthing\sto\sdo,\sbut\snot\swhat\sSQLite\shas\shistorically\sdone.\s(CVS\s4620)
-D 2007-12-13T02:45:31
+C ORDER\sBY\sin\sa\scompound\sSELECT\swill\sfirst\smatch\sagainst\sthe\sleft-most\sSELECT.\nIf\sthere\sis\sno\smatch\sthere,\sit\sbegins\sworking\sits\sway\sto\sthe\sright.\s(CVS\s4621)
+D 2007-12-13T03:45:08
 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
 F Makefile.in 0590398f62fc2c456ff4c45e9741f5a718b7e2ac
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -131,12 +131,12 @@ F src/pragma.c 0246032dbe681dded8710ac43eaf654eead1434e
 F src/prepare.c f811fdb6fd4a82cca673a6e1d5b041d6caf567f1
 F src/printf.c 5732e393c45be7c09bfca9a786daef017e0066ef
 F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
-F src/select.c 63cc67c9a9cc3f32ec2205d2c769d94cd2fc6f60
+F src/select.c c2de6d7ba6f98d83e03dabc405e46f439cb37f20
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c c97be281cfc3dcb14902f45e4b16f20038eb83ff
 F src/sqlite.h.in b16a7127dad4a3e5b1b26b3d64241f3373aa12ea
 F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
-F src/sqliteInt.h 5c390e902c88648035110d0fe156a279dcace271
+F src/sqliteInt.h 445530263725d19d6315f137f234aea08ad59303
 F src/sqliteLimit.h 3657c8eb75addce54a46354a29050a9673845a85
 F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
@@ -389,7 +389,7 @@ F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
 F test/misc7.test 3fbd0a9e3dd03331d9d76acd47bc179e1a97e15e
 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
 F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82
-F test/null.test 93e48033673841240f137fd621317cc73b69eeb8
+F test/null.test 6adcb4efd433e02c60499f96328014de87cff8b1
 F test/onefile.test b9cce375fd2a41ee3afa79a0a808954046b74458
 F test/openv2.test f5dd6b23e4dce828eb211649b600763c42a668df
 F test/pager.test 60303481b22b240c18d6dd1b64edcecc2f4b5a97
@@ -414,7 +414,7 @@ F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
 F test/select1.test 79784038f0e7df66bb420e149c6fb91e61e11fb7
 F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
 F test/select3.test 47439f28862489626b483b0c718cfb0562e6f6d5
-F test/select4.test 2dd28cfea6f50281fb29cf136cf50df8ead6a5d2
+F test/select4.test 566b4ca1152e16d7090d76f98d93c80b9a1f6c53
 F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce
 F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8
 F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f
@@ -600,7 +600,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P c0689409320de1532be0c0cae12b4b716f6bffb9
-R 1ec374c4daffe98452f78ad79abdb48f
+P bbddf16ac9539c7d48adfc73c5a90eecb8df6865
+R 377fa996f832a29c87d12a5f182c500b
 U drh
-Z 92df68b2adbb4d9afb7d6635a4dfe3d8
+Z f7fa31d1f83b3a0d837ffef0df0c17c3
index 3a7d141948a3463578932e03765348fc95c30bb6..9d727bd1d7eb18f819a2197833987650946208f1 100644 (file)
@@ -1 +1 @@
-bbddf16ac9539c7d48adfc73c5a90eecb8df6865
\ No newline at end of file
+56063ec84b130bcdb0e90bc76fabca394d0d867f
\ No newline at end of file
index 6c988f330c48ca6d7c010520ca408ec1d83d458f..553144f3fa5a85dc0a467424f6c4636e145c2231 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.366 2007/12/13 02:45:31 drh Exp $
+** $Id: select.c,v 1.367 2007/12/13 03:45:08 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1486,7 +1486,12 @@ static int matchOrderByTermToExprList(
   nc.allowAgg = 1;
   nc.nErr = 0;
   if( sqlite3ExprResolveNames(&nc, pE) ){
-    return -1;
+    if( isCompound ){
+      sqlite3ErrorClear(pParse);
+      return 0;
+    }else{
+      return -1;
+    }
   }
   if( nc.hasAgg && pHasAgg ){
     *pHasAgg = 1;
@@ -1501,12 +1506,8 @@ static int matchOrderByTermToExprList(
         return i+1;
       }
     }
-    sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any "
-       "column in the result set of the left-most SELECT", idx);
-    return -1;
-  }else{
-    return 0;
   }
+  return 0;
 }
 
 
@@ -1593,6 +1594,8 @@ static int processCompoundOrderBy(
   int i;
   ExprList *pOrderBy;
   ExprList *pEList;
+  sqlite3 *db;
+  int moreToDo = 1;
 
   pOrderBy = pSelect->pOrderBy;
   if( pOrderBy==0 ) return 0;
@@ -1600,31 +1603,58 @@ static int processCompoundOrderBy(
     sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
     return 1;
   }
+  db = pParse->db;
+  for(i=0; i<pOrderBy->nExpr; i++){
+    pOrderBy->a[i].done = 0;
+  }
   while( pSelect->pPrior ){
     pSelect = pSelect->pPrior;
   }
-  pEList = pSelect->pEList;
-  if( pEList==0 ){
-    return 1;
+  while( pSelect && moreToDo ){
+    moreToDo = 0;
+    for(i=0; i<pOrderBy->nExpr; i++){
+      int iCol;
+      Expr *pE;
+      if( pOrderBy->a[i].done ) continue;
+      pE = pOrderBy->a[i].pExpr;
+      Expr *pDup = sqlite3ExprDup(db, pE);
+      if( pDup==0 ){
+        return 1;
+      }
+      iCol = matchOrderByTermToExprList(pParse, pSelect, pDup, i+1, 1, 0);
+      sqlite3ExprDelete(pDup);
+      if( iCol<0 ){
+        return 1;
+      }
+      pEList = pSelect->pEList;
+      if( pEList==0 ){
+        return 1;
+      }
+      if( iCol>pEList->nExpr ){
+        sqlite3ErrorMsg(pParse, 
+           "%r ORDER BY term out of range - should be "
+           "between 1 and %d", i+1, pEList->nExpr);
+        return 1;
+      }
+      if( iCol>0 ){
+        pE->op = TK_COLUMN;
+        pE->iTable = iTable;
+        pE->iAgg = -1;
+        pE->iColumn = iCol-1;
+        pE->pTab = 0;
+        pOrderBy->a[i].done = 1;
+      }else{
+        moreToDo = 1;
+      }
+    }
+    pSelect = pSelect->pNext;
   }
   for(i=0; i<pOrderBy->nExpr; i++){
-    int iCol;
-    Expr *pE = pOrderBy->a[i].pExpr;
-    iCol = matchOrderByTermToExprList(pParse, pSelect, pE, i+1, 1, 0);
-    if( iCol<0 ){
-      return 1;
-    }
-    if( iCol>pEList->nExpr ){
-      sqlite3ErrorMsg(pParse, 
-         "%r ORDER BY term out of range - should be "
-         "between 1 and %d", i+1, pEList->nExpr);
+    if( pOrderBy->a[i].done==0 ){
+      sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any "
+            "column in the result set", i+1);
       return 1;
     }
-    pE->op = TK_COLUMN;
-    pE->iTable = iTable;
-    pE->iAgg = -1;
-    pE->iColumn = iCol-1;
-    pE->pTab = 0;
   }
   return 0;
 }
@@ -3033,10 +3063,12 @@ int sqlite3Select(
   */
   if( p->pPrior ){
     if( p->pRightmost==0 ){
-      Select *pLoop;
+      Select *pLoop, *pRight = 0;
       int cnt = 0;
       for(pLoop=p; pLoop; pLoop=pLoop->pPrior, cnt++){
         pLoop->pRightmost = p;
+        pLoop->pNext = pRight;
+        pRight = pLoop;
       }
       if( SQLITE_MAX_COMPOUND_SELECT>0 && cnt>SQLITE_MAX_COMPOUND_SELECT ){
         sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
index 635e93bcb638f39ad6a9bcb0447c3c58f3a681c2..825ca21e2bd7553ee2e7f1e0246aee65a96e958b 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.625 2007/12/11 19:34:45 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.626 2007/12/13 03:45:08 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1317,6 +1317,7 @@ struct Select {
   Expr *pHaving;         /* The HAVING clause */
   ExprList *pOrderBy;    /* The ORDER BY clause */
   Select *pPrior;        /* Prior select in a compound select statement */
+  Select *pNext;         /* Next select to the left in a compound */
   Select *pRightmost;    /* Right-most select in a compound select statement */
   Expr *pLimit;          /* LIMIT expression. NULL means not used. */
   Expr *pOffset;         /* OFFSET expression. NULL means not used. */
index 889252d01fb9172a24d0c6e6e1b5868fbe7b3dde..c6b202e8197797d9c7012eeeee9bd1861c9eb427 100644 (file)
@@ -150,7 +150,13 @@ do_test null-5.1 {
 } {{} 0 1}
 
 # A UNION to two queries should treat NULL values
-# as distinct
+# as distinct.
+#
+# (Later:)  We also take this opportunity to test the ability
+# of an ORDER BY clause to bind to either SELECT of a UNION.
+# The left-most SELECT is preferred.  In standard SQL, only
+# the left SELECT can be used.  The ability to match an ORDER
+# BY term to the right SELECT is an SQLite extension.
 #
 ifcapable compound {
   do_test null-6.1 {
@@ -173,6 +179,16 @@ ifcapable compound {
       select b from t1 union select c from t1 order by main.t1.b;
     }
   } {{} 0 1}
+  do_test null-6.5 {
+    execsql {
+      select b from t1 union select c from t1 order by t1.a;
+    }
+  } {{} 0 1}
+  do_test null-6.6 {
+    execsql {
+      select b from t1 union select c from t1 order by main.t1.a;
+    }
+  } {{} 0 1}
 } ;# ifcapable compound
 
 # The UNIQUE constraint only applies to non-null values
index 713abe75566c15a77c5637398614f981937f077d..df7dfee5fee55c082242969914d7e0479beb51c7 100644 (file)
@@ -12,7 +12,7 @@
 # focus of this file is testing UNION, INTERSECT and EXCEPT operators
 # in SELECT statements.
 #
-# $Id: select4.test,v 1.22 2007/12/10 18:51:48 danielk1977 Exp $
+# $Id: select4.test,v 1.23 2007/12/13 03:45:08 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -210,12 +210,15 @@ do_test select4-4.1.1 {
 
 do_test select4-4.1.2 {
   execsql {
-    SELECT DISTINCT log FROM t1 UNION ALL SELECT 6
+    SELECT DISTINCT log FROM t1
+    UNION ALL
+    SELECT 6
     INTERSECT
     SELECT n FROM t1 WHERE log=3
-    ORDER BY log;
+    ORDER BY t1.log;
   }
 } {5 6}
+
 do_test select4-4.1.3 {
   execsql {
     CREATE TABLE t2 AS