]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Select collation sequences for ORDER BY expressions attached to recursive CTEs in...
authordan <dan@noemail.net>
Fri, 24 Jan 2014 20:37:18 +0000 (20:37 +0000)
committerdan <dan@noemail.net>
Fri, 24 Jan 2014 20:37:18 +0000 (20:37 +0000)
FossilOrigin-Name: 9554519c126c5e714421a82fd2e8aa9b19e11493

manifest
manifest.uuid
src/select.c
test/with1.test

index d3ca0de3ef7c9761e37db4f058ceecdf143ab297..ebef0b5e83c6c6bfd2c76e82354753001788321f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sharmless\scompiler\swarnings\sin\sthe\sTcl\sinterface.
-D 2014-01-24T17:03:55.776
+C Select\scollation\ssequences\sfor\sORDER\sBY\sexpressions\sattached\sto\srecursive\sCTEs\sin\sthe\ssame\sway\sas\sthey\sare\sselected\sfor\sother\scompound\sSELECT\sstatements.
+D 2014-01-24T20:37:18.933
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -219,7 +219,7 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
 F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
-F src/select.c 93764e0d81946c070e2c7f1127f35e21efabbcc3
+F src/select.c d88d739b7af398b8d5b6856d1d479b42d15c419d
 F src/shell.c 24722d24d4ea8ca93db35e44db7308de786767ca
 F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
@@ -1092,7 +1092,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
 F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
-F test/with1.test 6c9c27b76e320d0ae3a3fc9ff6b236018201470d
+F test/with1.test ce15d69d34a2576b0e47d78c244d1ba2a31679d1
 F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
 F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
 F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
@@ -1152,7 +1152,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 67d6c42d44cb191368ce20f553b32fcb14bfc4d7
-R 4c6f56cfb9673c8d50f2c5c8d045a419
-U mistachkin
-Z 1e8effcea2fae186977e2dc88d96ee04
+P 35bc81f5ad4503c0db03127ba3c2ee4ce5227448
+R c1a71fcb2b287542b440975ad8562a1c
+U dan
+Z 0004644f36087f5d68980e2ae5cf51c5
index 6840f3457c392925b1e0a6bf0b8cc112bcc83522..7673b5df8f9fa7c41172986d0a796954a6c4c6ee 100644 (file)
@@ -1 +1 @@
-35bc81f5ad4503c0db03127ba3c2ee4ce5227448
\ No newline at end of file
+9554519c126c5e714421a82fd2e8aa9b19e11493
\ No newline at end of file
index 98ed526e08ef711cf62cb6b9a45bb6f9b74366f1..9efa822a8cd06bb6e5aa7192692aaf1b5c92fd6c 100644 (file)
@@ -1725,6 +1725,44 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
   }
   return pRet;
 }
+
+/*
+** The select statement passed as the second parameter is a compound SELECT
+** with an ORDER BY clause. This function allocates and returns a KeyInfo
+** structure suitable for implementing the ORDER BY.
+**
+** Space to hold the KeyInfo structure is obtained from malloc. The calling
+** function is responsible for ensuring that this structure is eventually
+** freed.
+*/
+static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
+  ExprList *pOrderBy = p->pOrderBy;
+  int nOrderBy = p->pOrderBy->nExpr;
+  sqlite3 *db = pParse->db;
+  KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
+  if( pRet ){
+    int i;
+    for(i=0; i<nOrderBy; i++){
+      struct ExprList_item *pItem = &pOrderBy->a[i];
+      Expr *pTerm = pItem->pExpr;
+      CollSeq *pColl;
+
+      if( pTerm->flags & EP_Collate ){
+        pColl = sqlite3ExprCollSeq(pParse, pTerm);
+      }else{
+        pColl = multiSelectCollSeq(pParse, p, pItem->u.x.iOrderByCol-1);
+        if( pColl==0 ) pColl = db->pDfltColl;
+        pOrderBy->a[i].pExpr =
+          sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
+      }
+      assert( sqlite3KeyInfoIsWriteable(pRet) );
+      pRet->aColl[i] = pColl;
+      pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder;
+    }
+  }
+
+  return pRet;
+}
 #endif /* SQLITE_OMIT_COMPOUND_SELECT */
 
 #ifndef SQLITE_OMIT_CTE
@@ -1799,6 +1837,7 @@ static void generateWithRecursiveQuery(
   regOffset = p->iOffset;
   p->pLimit = p->pOffset = 0;
   p->iLimit = p->iOffset = 0;
+  pOrderBy = p->pOrderBy;
 
   /* Locate the cursor number of the Current table */
   for(i=0; ALWAYS(i<pSrc->nSrc); i++){
@@ -1808,10 +1847,6 @@ static void generateWithRecursiveQuery(
     }
   }
 
-  /* Detach the ORDER BY clause from the compound SELECT */
-  pOrderBy = p->pOrderBy;
-  p->pOrderBy = 0;
-
   /* Allocate cursors numbers for Queue and Distinct.  The cursor number for
   ** the Distinct table must be exactly one greater than Queue in order
   ** for the SRT_DistTable and SRT_DistQueue destinations to work. */
@@ -1828,7 +1863,7 @@ static void generateWithRecursiveQuery(
   regCurrent = ++pParse->nMem;
   sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
   if( pOrderBy ){
-    KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 1);
+    KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1);
     sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0,
                       (char*)pKeyInfo, P4_KEYINFO);
     destQueue.pOrderBy = pOrderBy;
@@ -1841,6 +1876,9 @@ static void generateWithRecursiveQuery(
     p->selFlags |= SF_UsesEphemeral;
   }
 
+  /* Detach the ORDER BY clause from the compound SELECT */
+  p->pOrderBy = 0;
+
   /* Store the results of the setup-query in Queue. */
   rc = sqlite3Select(pParse, pSetup, &destQueue);
   if( rc ) goto end_of_recursive_query;
@@ -2625,24 +2663,7 @@ static int multiSelectOrderBy(
           && pItem->u.x.iOrderByCol<=p->pEList->nExpr );
       aPermute[i] = pItem->u.x.iOrderByCol - 1;
     }
-    pKeyMerge = sqlite3KeyInfoAlloc(db, nOrderBy, 1);
-    if( pKeyMerge ){
-      for(i=0; i<nOrderBy; i++){
-        CollSeq *pColl;
-        Expr *pTerm = pOrderBy->a[i].pExpr;
-        if( pTerm->flags & EP_Collate ){
-          pColl = sqlite3ExprCollSeq(pParse, pTerm);
-        }else{
-          pColl = multiSelectCollSeq(pParse, p, aPermute[i]);
-          if( pColl==0 ) pColl = db->pDfltColl;
-          pOrderBy->a[i].pExpr =
-             sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
-        }
-        assert( sqlite3KeyInfoIsWriteable(pKeyMerge) );
-        pKeyMerge->aColl[i] = pColl;
-        pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder;
-      }
-    }
+    pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
   }else{
     pKeyMerge = 0;
   }
index 486f025c64fc1f382e0568a56b8e468ea119c6af..2fca12817f203e5e045f927c8488a0fcc1b838af 100644 (file)
@@ -607,6 +607,97 @@ do_test 10.6 {
 }]
 
 
+# Test name resolution in ORDER BY clauses.
+#
+do_catchsql_test 10.7.1 {
+  WITH t(a) AS (
+    SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY a
+  ) 
+  SELECT * FROM t
+} {1 {1st ORDER BY term does not match any column in the result set}}
+do_execsql_test 10.7.2 {
+  WITH t(a) AS (
+    SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY b
+  ) 
+  SELECT * FROM t
+} {1 2 3 4 5}
+do_execsql_test 10.7.3 {
+  WITH t(a) AS (
+    SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY c
+  ) 
+  SELECT * FROM t
+} {1 2 3 4 5}
+
+# Test COLLATE clauses attached to ORDER BY.
+#
+insert_into_tree {
+  /a/b
+  /a/C
+  /a/d
+  /B/e
+  /B/F
+  /B/g
+  /c/h
+  /c/I
+  /c/j
+}
+
+do_execsql_test 10.8.1 {
+  WITH flat(fid, depth, p) AS (
+    SELECT id, 1, '/' || payload FROM tree WHERE parentid IS NULL
+    UNION ALL
+    SELECT id, depth+1, p||'/'||payload FROM flat, tree WHERE parentid=fid
+    ORDER BY 2, 3 COLLATE nocase
+  )
+  SELECT p FROM flat;
+} {
+  /a /B /c
+  /a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j
+}
+do_execsql_test 10.8.2 {
+  WITH flat(fid, depth, p) AS (
+      SELECT id, 1, ('/' || payload) COLLATE nocase 
+      FROM tree WHERE parentid IS NULL
+    UNION ALL
+      SELECT id, depth+1, (p||'/'||payload)
+      FROM flat, tree WHERE parentid=fid
+    ORDER BY 2, 3
+  )
+  SELECT p FROM flat;
+} {
+  /a /B /c
+  /a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j
+}
+
+do_execsql_test 10.8.3 {
+  WITH flat(fid, depth, p) AS (
+      SELECT id, 1, ('/' || payload)
+      FROM tree WHERE parentid IS NULL
+    UNION ALL
+      SELECT id, depth+1, (p||'/'||payload) COLLATE nocase 
+      FROM flat, tree WHERE parentid=fid
+    ORDER BY 2, 3
+  )
+  SELECT p FROM flat;
+} {
+  /a /B /c
+  /a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j
+}
+
+do_execsql_test 10.8.4.1 {
+  CREATE TABLE tst(a,b);
+  INSERT INTO tst VALUES('a', 'A');
+  INSERT INTO tst VALUES('b', 'B');
+  INSERT INTO tst VALUES('c', 'C');
+  SELECT a COLLATE nocase FROM tst UNION ALL SELECT b FROM tst ORDER BY 1;
+} {a A b B c C}
+do_execsql_test 10.8.4.2 {
+  SELECT a FROM tst UNION ALL SELECT b COLLATE nocase FROM tst ORDER BY 1;
+} {A B C a b c}
+do_execsql_test 10.8.4.3 {
+  SELECT a||'' FROM tst UNION ALL SELECT b COLLATE nocase FROM tst ORDER BY 1;
+} {a A b B c C}
+
 # Test cases to illustrate on the ORDER BY clause on a recursive query can be
 # used to control depth-first versus breath-first search in a tree.
 #