diff options
-rw-r--r-- | manifest | 16 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/parse.y | 21 | ||||
-rw-r--r-- | src/select.c | 31 | ||||
-rw-r--r-- | test/limit.test | 42 |
5 files changed, 80 insertions, 32 deletions
@@ -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 diff --git a/manifest.uuid b/manifest.uuid index 30130317d..f042c9c32 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -96e3c539586bf86c4fe8de0ac25de6655f704035
\ No newline at end of file +e6a752bfef24f773973c151c6262ff331a9dc57a
\ No newline at end of file diff --git a/src/parse.y b/src/parse.y index f3b979516..4efb90ed7 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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 ///////////////////////////// // diff --git a/src/select.c b/src/select.c index 5b0d37569..22df1d15e 100644 --- a/src/select.c +++ b/src/select.c @@ -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 diff --git a/test/limit.test b/test/limit.test index b07f644da..286d2fcbb 100644 --- a/test/limit.test +++ b/test/limit.test @@ -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 |