]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Allow negative values for LIMIT and OFFSET. Add tests for negative LIMITs
authordrh <drh@noemail.net>
Wed, 16 Jul 2003 02:19:37 +0000 (02:19 +0000)
committerdrh <drh@noemail.net>
Wed, 16 Jul 2003 02:19:37 +0000 (02:19 +0000)
and OFFSETs.  Make the OFFSET work even if LIMIT is 0 or negative. (CVS 1052)

FossilOrigin-Name: e6a752bfef24f773973c151c6262ff331a9dc57a

manifest
manifest.uuid
src/parse.y
src/select.c
test/limit.test

index f3a9d69e3bb2512feffd287d11065587fea57b08..7d6a550819ddf15487df59bfb3f0955057f51dcf 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Initialize\sa\svariable\sto\sprevent\san\sMSVC\scompiler\swarning.\s\sTicket\s#394.\s(CVS\s1051)
-D 2003-07-16T00:54:31
+C Allow\snegative\svalues\sfor\sLIMIT\sand\sOFFSET.\s\sAdd\stests\sfor\snegative\sLIMITs\nand\sOFFSETs.\s\sMake\sthe\sOFFSET\swork\seven\sif\sLIMIT\sis\s0\sor\snegative.\s(CVS\s1052)
+D 2003-07-16T02:19:38
 F Makefile.in 9ad23ed4ca97f9670c4496432e3fbd4b3760ebde
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -39,11 +39,11 @@ F src/os.c 0d5252d60c1b0f21a343b18248d3dfcafb94e621
 F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
 F src/pager.c 9512e789dbd5acaf91e74c4665e03c2734d3da25
 F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31
-F src/parse.y 917250e5d86bdee752355e6617ea2e8ee12438bf
+F src/parse.y 16aed0e3ed05445fa7f6a4209cc054208c7083c0
 F src/pragma.c 3b4f5a800e7a2145bc1930f323232e297d4eb782
 F src/printf.c 12e45d482ac8abcc6f786fc99e5bed7dd9a51af0
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c 29c53228a4e66bfcebd797b7539678fcd0e2cf64
+F src/select.c 20a38bc2a63cc2676651013421cdb6a796c017af
 F src/shell.c 3ed268908fd69c8fd4b28dbe415075cbf0e3991a
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 54619fa5df4c83b22def66bb3d24808fd03dcbae
@@ -89,7 +89,7 @@ F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f
 F test/intpkey.test 9320af48415c594afd4e15f8ef0daa272e05502e
 F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4
 F test/join.test 54e770b74fc8cfc7769d5d0bb05657085641b3c4
-F test/limit.test 9ffb965a0f5bf7152187ef3d8d1249b96e5620bf
+F test/limit.test 10991f3f33159a58b42859df3c731cfaf412c76e
 F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473
 F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d
 F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
@@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3
 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
-P 6a07ac3782bc18f907ffcf66d908ddaa82ab9293
-R 60816c1f9d14c21b4d74e100abc8c1fe
+P 96e3c539586bf86c4fe8de0ac25de6655f704035
+R d3b2a0cf306874e50accca7303d95b51
 U drh
-Z da6e7a70e113773ece5e492f9f39d7ac
+Z 6453ea102fcd7011423a94e154aded18
index 30130317d23f7685b97275ce644c8ae236342c9b..f042c9c32dcadb7fbccc6675c3d02493c4b34e47 100644 (file)
@@ -1 +1 @@
-96e3c539586bf86c4fe8de0ac25de6655f704035
\ No newline at end of file
+e6a752bfef24f773973c151c6262ff331a9dc57a
\ No newline at end of file
index f3b979516d8242c51910cb26195839bb93ccbaa4..4efb90ed761fe3ee4cc67d4963e3a5c07e2e4d33 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.98 2003/05/17 19:04:04 drh Exp $
+** @(#) $Id: parse.y,v 1.99 2003/07/16 02:19:38 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -153,9 +153,10 @@ type ::= typename(X) LP signed COMMA signed RP(Y).
 %type typename {Token}
 typename(A) ::= ids(X).           {A = X;}
 typename(A) ::= typename(X) ids.  {A = X;}
-signed ::= INTEGER.
-signed ::= PLUS INTEGER.
-signed ::= MINUS INTEGER.
+%type signed {int}
+signed(A) ::= INTEGER(X).         { A = atoi(X.z); }
+signed(A) ::= PLUS INTEGER(X).    { A = atoi(X.z); }
+signed(A) ::= MINUS INTEGER(X).   { A = -atoi(X.z); }
 carglist ::= carglist carg.
 carglist ::= .
 carg ::= CONSTRAINT nm ccons.
@@ -442,12 +443,12 @@ having_opt(A) ::= .                {A = 0;}
 having_opt(A) ::= HAVING expr(X).  {A = X;}
 
 %type limit_opt {struct LimitVal}
-limit_opt(A) ::= .                  {A.limit = -1; A.offset = 0;}
-limit_opt(A) ::= LIMIT INTEGER(X).  {A.limit = atoi(X.z); A.offset = 0;}
-limit_opt(A) ::= LIMIT INTEGER(X) OFFSET INTEGER(Y). 
-                                    {A.limit = atoi(X.z); A.offset = atoi(Y.z);}
-limit_opt(A) ::= LIMIT INTEGER(X) COMMA INTEGER(Y). 
-                                    {A.limit = atoi(Y.z); A.offset = atoi(X.z);}
+limit_opt(A) ::= .                     {A.limit = -1; A.offset = 0;}
+limit_opt(A) ::= LIMIT signed(X).      {A.limit = X; A.offset = 0;}
+limit_opt(A) ::= LIMIT signed(X) OFFSET signed(Y). 
+                                       {A.limit = X; A.offset = Y;}
+limit_opt(A) ::= LIMIT signed(X) COMMA signed(Y). 
+                                       {A.limit = Y; A.offset = X;}
 
 /////////////////////////// The DELETE statement /////////////////////////////
 //
index 5b0d3756959cf1765308b65f9ad2e0415fd72191..22df1d15eebac609d00df37021bdcc83cce6b52a 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.141 2003/06/16 00:40:35 drh Exp $
+** $Id: select.c,v 1.142 2003/07/16 02:19:38 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -30,7 +30,7 @@ Select *sqliteSelectNew(
   ExprList *pOrderBy,   /* the ORDER BY clause */
   int isDistinct,       /* true if the DISTINCT keyword is present */
   int nLimit,           /* LIMIT value.  -1 means not used */
-  int nOffset           /* OFFSET value.  -1 means not used */
+  int nOffset           /* OFFSET value.  0 means no offset */
 ){
   Select *pNew;
   pNew = sqliteMalloc( sizeof(*pNew) );
@@ -2140,24 +2140,31 @@ int sqliteSelect(
     generateColumnNames(pParse, pTabList, pEList);
   }
 
-  /* Set the limiter
+  /* Set the limiter.
+  **
+  ** The phrase "LIMIT 0" means all rows are shown, not zero rows.
+  ** If the comparison is p->nLimit<=0 then "LIMIT 0" shows
+  ** all rows.  It is the same as no limit. If the comparision is
+  ** p->nLimit<0 then "LIMIT 0" show no rows at all.
+  ** "LIMIT -1" always shows all rows.  There is some
+  ** contraversy about what the correct behavior should be.
   */
   if( p->nLimit<=0 ){
     p->nLimit = -1;
-    p->nOffset = 0;
   }else{
     int iMem = pParse->nMem++;
     sqliteVdbeAddOp(v, OP_Integer, -p->nLimit, 0);
     sqliteVdbeAddOp(v, OP_MemStore, iMem, 1);
     p->nLimit = iMem;
-    if( p->nOffset<=0 ){
-      p->nOffset = 0;
-    }else{
-      iMem = pParse->nMem++;
-      sqliteVdbeAddOp(v, OP_Integer, -p->nOffset, 0);
-      sqliteVdbeAddOp(v, OP_MemStore, iMem, 1);
-      p->nOffset = iMem;
-    }
+  }
+  if( p->nOffset<=0 ){
+    p->nOffset = 0;
+  }else{
+    int iMem = pParse->nMem++;
+    if( iMem==0 ) iMem = pParse->nMem++;
+    sqliteVdbeAddOp(v, OP_Integer, -p->nOffset, 0);
+    sqliteVdbeAddOp(v, OP_MemStore, iMem, 1);
+    p->nOffset = iMem;
   }
 
   /* Generate code for all sub-queries in the FROM clause
index b07f644da3045f31f550d311b924b62c228cafb4..286d2fcbb4ccaf90b6b572ff4b3f70125b86b327 100644 (file)
@@ -12,7 +12,7 @@
 # focus of this file is testing the LIMIT ... OFFSET ... clause
 #  of SELECT statements.
 #
-# $Id: limit.test,v 1.7 2003/02/20 00:44:53 drh Exp $
+# $Id: limit.test,v 1.8 2003/07/16 02:19:38 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -163,4 +163,44 @@ do_test limit-5.5 {
   }
 } {1000 1528204 593161 0 3107 505 1005}
 
+# There is some contraversy about whether LIMIT 0 should be the same as
+# no limit at all or if LIMIT 0 should result in zero output rows.
+#
+do_test limit-6.1 {
+  execsql {
+    BEGIN;
+    CREATE TABLE t6(a);
+    INSERT INTO t6 VALUES(1);
+    INSERT INTO t6 VALUES(2);
+    INSERT INTO t6 SELECT a+2 FROM t6;
+    COMMIT;
+    SELECT * FROM t6;
+  }
+} {1 2 3 4}
+do_test limit-6.2 {
+  execsql {
+    SELECT * FROM t6 LIMIT -1 OFFSET -1;
+  }
+} {1 2 3 4}
+do_test limit-6.3 {
+  execsql {
+    SELECT * FROM t6 LIMIT 2 OFFSET -123;
+  }
+} {1 2}
+do_test limit-6.4 {
+  execsql {
+    SELECT * FROM t6 LIMIT -432 OFFSET 2;
+  }
+} {3 4}
+do_test limit-6.5 {
+  execsql {
+    SELECT * FROM t6 LIMIT 0
+  }
+} {1 2 3 4}
+do_test limit-6.6 {
+  execsql {
+    SELECT * FROM t6 LIMIT 0 OFFSET 1
+  }
+} {2 3 4}
+
 finish_test