]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance the ORDER BY clause so that an integer term means to sort by the
authordrh <drh@noemail.net>
Sun, 2 Jun 2002 16:09:01 +0000 (16:09 +0000)
committerdrh <drh@noemail.net>
Sun, 2 Jun 2002 16:09:01 +0000 (16:09 +0000)
corresponding column. (CVS 602)

FossilOrigin-Name: 7acbf84b492202d8b5a05276a95b475027eb5f58

manifest
manifest.uuid
src/expr.c
src/select.c
src/sqliteInt.h
test/select1.test
test/select4.test

index fd0af44d60f0744494d4f4fd6263deeb7ddb6afc..b8c64658d298cba7d1604e79182933ae77f6a60f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Multiplying\sNULL\sby\szero\sgives\sNULL,\snot\szero.\s\sI\smisread\sthe\stest\sdata\nand\scoded\sit\swrong.\s\sThis\scheck-in\sfixes\sthe\sproblem.\s(CVS\s601)
-D 2002-06-01T21:41:10
+C Enhance\sthe\sORDER\sBY\sclause\sso\sthat\san\sinteger\sterm\smeans\sto\ssort\sby\sthe\ncorresponding\scolumn.\s(CVS\s602)
+D 2002-06-02T16:09:02
 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
 F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -23,7 +23,7 @@ F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
 F src/build.c 36e42718a7a94f554ea39508993378482f5335c7
 F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523
 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
-F src/expr.c 6bb74762c3d86b1665b32a6a388a70eeaaca93f8
+F src/expr.c 4ee07b536119e7ee4f572e1ca83ad86c1aef0058
 F src/func.c 061a520a122da7e4f9dcac15697bb996aac7d5df
 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
 F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
@@ -37,11 +37,11 @@ F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
 F src/parse.y c681da701bf142967325b8791f22418e2d81552d
 F src/printf.c d8032ee18b860c812eeff596c9bebfdacb7930fd
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c 9a9f76d7d647284f41616bc120003961bea403ef
+F src/select.c ad9061b4735ccd79fc073415979882cd5c424c71
 F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
-F src/sqliteInt.h 55824b7c87dcead71801354f90e4f1b1481f1d1e
+F src/sqliteInt.h 8ec47ae045cf8525c2bcc1a650853d814ca7675c
 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
 F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
 F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e
@@ -87,10 +87,10 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
 F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
 F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
 F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
-F test/select1.test a19a8026b5c2c5bdf5384d761f3d446954b7ebf9
+F test/select1.test 0d708cec567104653ec9aa49fecf3444a2e7d150
 F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
 F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
-F test/select4.test 32018b97fde7202dcb906748836fcd79410604d3
+F test/select4.test 9b5c87b7a372172d65928cf860bcd5a54694c775
 F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
 F test/select6.test efb8d0c07a440441db87db2c4ade6904e1407e85
 F test/sort.test 3b996ce7ca385f9cd559944ac0f4027a23aa546b
@@ -136,7 +136,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P da61aa1d238539dff9c43fd9f464d311e28d669f
-R f5c3f541431552f938b5386e692916f8
+P df9cc852ad02dbec5558d3915a0303f7e7b79b2b
+R d820e9b413015f44b726f7ec86a28058
 U drh
-Z 64d47e65013a776dcf32882cb49edbc6
+Z 52b5b2062ca7af0b018c152f36b11673
index 1659a80ea64f797359693328fdab4fa9173455b7..56899c72e71b902e8c15272bbde1c720ec0ca399 100644 (file)
@@ -1 +1 @@
-df9cc852ad02dbec5558d3915a0303f7e7b79b2b
\ No newline at end of file
+7acbf84b492202d8b5a05276a95b475027eb5f58
\ No newline at end of file
index c414e3937756c262bb0cc5ed15bb754fc578467d..b5bb89c99e016acff857a4c236ffdd4b7d951954 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.66 2002/05/31 15:51:25 drh Exp $
+** $Id: expr.c,v 1.67 2002/06/02 16:09:02 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -335,6 +335,41 @@ int sqliteExprIsConstant(Expr *p){
   return 0;
 }
 
+/*
+** If the given expression codes a constant integer, return 1 and put
+** the value of the integer in *pValue.  If the expression is not an
+** integer, return 0 and leave *pValue unchanged.
+*/
+int sqliteExprIsInteger(Expr *p, int *pValue){
+  switch( p->op ){
+    case TK_INTEGER: {
+      *pValue = atoi(p->token.z);
+      return 1;
+    }
+    case TK_STRING: {
+      char *z = p->token.z;
+      int n = p->token.n;
+      if( n>0 && z=='-' ){ z++; n--; }
+      while( n>0 && *z && isdigit(*z) ){ z++; n--; }
+      if( n==0 ){
+        *pValue = atoi(p->token.z);
+        return 1;
+      }
+      break;
+    }
+    case TK_UMINUS: {
+      int v;
+      if( sqliteExprIsInteger(p->pLeft, &v) ){
+        *pValue = -v;
+        return 1;
+      }
+      break;
+    }
+    default: break;
+  }
+  return 0;
+}
+
 /*
 ** Return TRUE if the given string is a row-id column name.
 */
index 5a97be8dda2768db53b02e93e893456396db9479..708305a3315d7ac0ea08770e5ac094b4c6309501 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.89 2002/05/31 15:51:25 drh Exp $
+** $Id: select.c,v 1.90 2002/06/02 16:09:02 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -790,7 +790,7 @@ static int matchOrderbyToColumn(
   Parse *pParse,          /* A place to leave error messages */
   Select *pSelect,        /* Match to result columns of this SELECT */
   ExprList *pOrderBy,     /* The ORDER BY values to match against columns */
-  int iTable,             /* Insert this this value in iTable */
+  int iTable,             /* Insert this value in iTable */
   int mustComplete        /* If TRUE all ORDER BYs must match */
 ){
   int nErr = 0;
@@ -812,9 +812,21 @@ static int matchOrderbyToColumn(
   pEList = pSelect->pEList;
   for(i=0; i<pOrderBy->nExpr; i++){
     Expr *pE = pOrderBy->a[i].pExpr;
-    int match = 0;
+    int iCol = -1;
     if( pOrderBy->a[i].done ) continue;
-    for(j=0; j<pEList->nExpr; j++){
+    if( sqliteExprIsInteger(pE, &iCol) ){
+      if( iCol<=0 || iCol>pEList->nExpr ){
+        char zBuf[200];
+        sprintf(zBuf,"ORDER BY position %d should be between 1 and %d",
+           iCol, pEList->nExpr);
+        sqliteSetString(&pParse->zErrMsg, zBuf, 0);
+        pParse->nErr++;
+        nErr++;
+        break;
+      }
+      iCol--;
+    }
+    for(j=0; iCol<0 && j<pEList->nExpr; j++){
       if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
         char *zName, *zLabel;
         zName = pEList->a[j].zName;
@@ -822,22 +834,21 @@ static int matchOrderbyToColumn(
         zLabel = sqliteStrNDup(pE->token.z, pE->token.n);
         sqliteDequote(zLabel);
         if( sqliteStrICmp(zName, zLabel)==0 ){ 
-          match = 1; 
+          iCol = j;
         }
         sqliteFree(zLabel);
       }
-      if( match==0 && sqliteExprCompare(pE, pEList->a[j].pExpr) ){
-        match = 1;
-      }
-      if( match ){
-        pE->op = TK_COLUMN;
-        pE->iColumn = j;
-        pE->iTable = iTable;
-        pOrderBy->a[i].done = 1;
-        break;
+      if( iCol<0 && sqliteExprCompare(pE, pEList->a[j].pExpr) ){
+        iCol = j;
       }
     }
-    if( !match && mustComplete ){
+    if( iCol>=0 ){
+      pE->op = TK_COLUMN;
+      pE->iColumn = iCol;
+      pE->iTable = iTable;
+      pOrderBy->a[i].done = 1;
+    }
+    if( iCol<0 && mustComplete ){
       char zBuf[30];
       sprintf(zBuf,"%d",i+1);
       sqliteSetString(&pParse->zErrMsg, "ORDER BY term number ", zBuf, 
@@ -1520,10 +1531,22 @@ int sqliteSelect(
     for(i=0; i<pOrderBy->nExpr; i++){
       Expr *pE = pOrderBy->a[i].pExpr;
       if( sqliteExprIsConstant(pE) ){
-        sqliteSetString(&pParse->zErrMsg, 
-             "ORDER BY expressions should not be constant", 0);
-        pParse->nErr++;
-        goto select_end;
+        int iCol;
+        if( sqliteExprIsInteger(pE, &iCol)==0 ){
+          sqliteSetString(&pParse->zErrMsg, 
+               "ORDER BY terms must not be non-integer constants", 0);
+          pParse->nErr++;
+          goto select_end;
+        }else if( iCol<=0 || iCol>pEList->nExpr ){
+          char zBuf[2000];
+          sprintf(zBuf,"ORDER BY column number %d out of range - should be "
+             "between 1 and %d", iCol, pEList->nExpr);
+          sqliteSetString(&pParse->zErrMsg, zBuf, 0);
+          pParse->nErr++;
+          goto select_end;
+        }
+        sqliteExprDelete(pE);
+        pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr);
       }
       if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pE) ){
         goto select_end;
index 77154dc61ff82196922bd7e8234a8ef3857aa78e..8855b109b0ba5b0f93ec0e6279c192ece0372791 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.118 2002/05/27 12:24:49 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.119 2002/06/02 16:09:02 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -841,6 +841,7 @@ void sqliteCommitTransaction(Parse*);
 void sqliteRollbackTransaction(Parse*);
 char *sqlite_mprintf(const char *, ...);
 int sqliteExprIsConstant(Expr*);
+int sqliteExprIsInteger(Expr*, int*);
 void sqliteGenerateRowDelete(Vdbe*, Table*, int, int);
 void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
 void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
index 6d3e45d360bf18a12c871104dcb1b946618bfefa..b7624c0836267ba510d90e1f2eefea9e1f1ef348 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: select1.test,v 1.29 2002/05/29 23:22:23 drh Exp $
+# $Id: select1.test,v 1.30 2002/06/02 16:09:03 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -285,7 +285,52 @@ do_test select1-4.5 {
   catchsql {
     SELECT f1 FROM test1 ORDER BY 8.4;
   }
-} {1 {ORDER BY expressions should not be constant}}
+} {1 {ORDER BY terms must not be non-integer constants}}
+do_test select1-4.6 {
+  catchsql {
+    SELECT f1 FROM test1 ORDER BY '8.4';
+  }
+} {1 {ORDER BY terms must not be non-integer constants}}
+do_test select1-4.7 {
+  catchsql {
+    SELECT f1 FROM test1 ORDER BY 'xyz';
+  }
+} {1 {ORDER BY terms must not be non-integer constants}}
+do_test select1-4.8 {
+  execsql {
+    CREATE TABLE t5(a,b);
+    INSERT INTO t5 VALUES(1,10);
+    INSERT INTO t5 VALUES(2,9);
+    SELECT * FROM t5 ORDER BY 1;
+  }
+} {1 10 2 9}
+do_test select1-4.9 {
+  execsql {
+    SELECT * FROM t5 ORDER BY 2;
+  }
+} {2 9 1 10}
+do_test select1-4.10 {
+  catchsql {
+    SELECT * FROM t5 ORDER BY 3;
+  }
+} {1 {ORDER BY column number 3 out of range - should be between 1 and 2}}
+do_test select1-4.11 {
+  execsql {
+    INSERT INTO t5 VALUES(3,10);
+    SELECT * FROM t5 ORDER BY 2, 1 DESC;
+  }
+} {2 9 3 10 1 10}
+do_test select1-4.12 {
+  execsql {
+    SELECT * FROM t5 ORDER BY 1 DESC, b;
+  }
+} {3 10 2 9 1 10}
+do_test select1-4.13 {
+  execsql {
+    SELECT * FROM t5 ORDER BY b DESC, 1;
+  }
+} {1 10 3 10 2 9}
+
 
 # ORDER BY ignored on an aggregate query
 #
index dc412a058bcab1e091700e6deba31dfd2ffc6745..c586641476ae7bd5454764fa3012e63f93db24e9 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.9 2002/05/31 15:51:26 drh Exp $
+# $Id: select4.test,v 1.10 2002/06/02 16:09:03 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -209,6 +209,54 @@ do_test select4-5.2e {
   }} msg]
   lappend v $msg
 } {0 {0 1 2 3 4 5 5 6 7 8}}
+do_test select4-5.2f {
+  catchsql {
+    SELECT DISTINCT log FROM t1
+    UNION ALL
+    SELECT n FROM t1 WHERE log=3
+    ORDER BY log;
+  }
+} {0 {0 1 2 3 4 5 5 6 7 8}}
+do_test select4-5.2g {
+  catchsql {
+    SELECT DISTINCT log FROM t1
+    UNION ALL
+    SELECT n FROM t1 WHERE log=3
+    ORDER BY 1;
+  }
+} {0 {0 1 2 3 4 5 5 6 7 8}}
+do_test select4-5.2h {
+  catchsql {
+    SELECT DISTINCT log FROM t1
+    UNION ALL
+    SELECT n FROM t1 WHERE log=3
+    ORDER BY 2;
+  }
+} {1 {ORDER BY position 2 should be between 1 and 1}}
+do_test select4-5.2i {
+  catchsql {
+    SELECT DISTINCT 1, log FROM t1
+    UNION ALL
+    SELECT 2, n FROM t1 WHERE log=3
+    ORDER BY 2, 1;
+  }
+} {0 {1 0 1 1 1 2 1 3 1 4 1 5 2 5 2 6 2 7 2 8}}
+do_test select4-5.2j {
+  catchsql {
+    SELECT DISTINCT 1, log FROM t1
+    UNION ALL
+    SELECT 2, n FROM t1 WHERE log=3
+    ORDER BY 1, 2 DESC;
+  }
+} {0 {1 5 1 4 1 3 1 2 1 1 1 0 2 8 2 7 2 6 2 5}}
+do_test select4-5.2k {
+  catchsql {
+    SELECT DISTINCT 1, log FROM t1
+    UNION ALL
+    SELECT 2, n FROM t1 WHERE log=3
+    ORDER BY n, 1;
+  }
+} {0 {1 0 1 1 1 2 1 3 1 4 1 5 2 5 2 6 2 7 2 8}}
 do_test select4-5.3 {
   set v [catch {execsql {
     SELECT DISTINCT log, n FROM t1