mirror of
				https://github.com/sqlite/sqlite.git
				synced 2025-10-31 18:11:01 +03:00 
			
		
		
		
	Allow expressions (including variables) in LIMIT and OFFSET clauses. Ticket #1096. (CVS 2316)
FossilOrigin-Name: 515e5033a5482f55e7edb66d69ff3da7e234ff2e
This commit is contained in:
		
							
								
								
									
										26
									
								
								manifest
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								manifest
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| C Add\sa\snumeric\sversion\snumber.\sTicket\s#1097.\s(CVS\s2315) | C Allow\sexpressions\s(including\svariables)\sin\sLIMIT\sand\sOFFSET\sclauses.\sTicket\s#1096.\s(CVS\s2316) | ||||||
| D 2005-02-05T07:33:34 | D 2005-02-05T12:48:48 | ||||||
| F Makefile.in d928187101fa3d78426cf48ca30e39d0fb714e57 | F Makefile.in d928187101fa3d78426cf48ca30e39d0fb714e57 | ||||||
| F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 | F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 | ||||||
| F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 | F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 | ||||||
| @@ -35,7 +35,7 @@ F src/build.c fcb437bcda09a57b3fe898dff5ff558e7536621b | |||||||
| F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f | F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f | ||||||
| F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3 | F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3 | ||||||
| F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad | F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad | ||||||
| F src/expr.c 2ed29dc4f8feeb55eafa40d41941ad7909666863 | F src/expr.c 1b6b6b16bcb6a6dcc4a5df451d9e652f84b269ae | ||||||
| F src/func.c f096b6771cc0aaa11790aca95773a50a8f74ba73 | F src/func.c f096b6771cc0aaa11790aca95773a50a8f74ba73 | ||||||
| F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f | F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f | ||||||
| F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 | F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 | ||||||
| @@ -53,14 +53,14 @@ F src/os_win.c bddeae1c3299be0fbe47077dd4e98b786a067f71 | |||||||
| F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b | F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b | ||||||
| F src/pager.c d21565d0e844712809140632062a7b72b768fdff | F src/pager.c d21565d0e844712809140632062a7b72b768fdff | ||||||
| F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 | F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 | ||||||
| F src/parse.y 7a4965d65c6c8a1f5012bf365c54c8dea09a3921 | F src/parse.y ee046c1ea30425a817285e52fb1993c2f955e766 | ||||||
| F src/pragma.c 572d7dd4f9c9d020ca2967a1c3ec02c3126e9631 | F src/pragma.c 572d7dd4f9c9d020ca2967a1c3ec02c3126e9631 | ||||||
| F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 | F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 | ||||||
| F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 | F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 | ||||||
| F src/select.c 16c750c000f0d6aa543c778e2c752154b7272336 | F src/select.c 6217e1f72cee7e173b21b252fd42a052f3b4decc | ||||||
| F src/shell.c 3cb0ef124ed9cd582ce89aec59ff7c659bc6e61b | F src/shell.c 3cb0ef124ed9cd582ce89aec59ff7c659bc6e61b | ||||||
| F src/sqlite.h.in c85f6bad9ca7de29f505fe886646cfff7df4c55e | F src/sqlite.h.in c85f6bad9ca7de29f505fe886646cfff7df4c55e | ||||||
| F src/sqliteInt.h f10da39b6407af63002401c7f9cee4a1313f4d2d | F src/sqliteInt.h 58e9365c0f575ef42973439caf3bbab450ad700b | ||||||
| F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 | F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 | ||||||
| F src/tclsqlite.c 101994a2c4c0eaa69f1de9bfe4a02167f6049e7d | F src/tclsqlite.c 101994a2c4c0eaa69f1de9bfe4a02167f6049e7d | ||||||
| F src/test1.c feac8a742aca920c8ab18a43b3208ae3a834fe9d | F src/test1.c feac8a742aca920c8ab18a43b3208ae3a834fe9d | ||||||
| @@ -73,8 +73,8 @@ F src/trigger.c 038c8e128d4551cd016426cd11bbf5c478816481 | |||||||
| F src/update.c b6f4668c11059f86b71581187d09197fa28ec4be | F src/update.c b6f4668c11059f86b71581187d09197fa28ec4be | ||||||
| F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c | F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c | ||||||
| F src/util.c 1b7b9a127b66743ab6cba8d44597aeb570723c99 | F src/util.c 1b7b9a127b66743ab6cba8d44597aeb570723c99 | ||||||
| F src/vacuum.c 14d1c346234fc64b326c19ea1ffe8f9e4c73d19a | F src/vacuum.c 4dbe45a5c41674a04ac45a7586031583386ab119 | ||||||
| F src/vdbe.c d2c29d2ada955818afa910c3204e5a5d145ceaea | F src/vdbe.c 5acf43749f44b0813d47f4b1801538f4aaa7ddbb | ||||||
| F src/vdbe.h bb9186484f749a839c6c43953e79a6530253f7cd | F src/vdbe.h bb9186484f749a839c6c43953e79a6530253f7cd | ||||||
| F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e | F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e | ||||||
| F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac | F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac | ||||||
| @@ -113,7 +113,7 @@ F test/collate4.test b8668612691c4dcf90f67a8df1eeb1544e7fdaf8 | |||||||
| F test/collate5.test 581775b94604b7435dc6a5c6e72fbbf7d69e3830 | F test/collate5.test 581775b94604b7435dc6a5c6e72fbbf7d69e3830 | ||||||
| F test/collate6.test 6c9470d1606ee3e564675b229653e320c49ec638 | F test/collate6.test 6c9470d1606ee3e564675b229653e320c49ec638 | ||||||
| F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87 | F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87 | ||||||
| F test/corrupt.test 34e031add52cb1f50aff722f7d4ebd7b972637d3 | F test/corrupt.test c34304baf2f027e05942af2efeb26844adca9a53 | ||||||
| F test/corrupt2.test 88342570828f2b8cbbd8369eff3891f5c0bdd5ba | F test/corrupt2.test 88342570828f2b8cbbd8369eff3891f5c0bdd5ba | ||||||
| F test/crash.test f38b980a0508655d08c957a6dd27d66bca776504 | F test/crash.test f38b980a0508655d08c957a6dd27d66bca776504 | ||||||
| F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 | F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 | ||||||
| @@ -143,7 +143,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 | |||||||
| F test/join4.test cc6cafe85e11aacacd0abcd247a46bed251308f8 | F test/join4.test cc6cafe85e11aacacd0abcd247a46bed251308f8 | ||||||
| F test/lastinsert.test b6a1db3e1ce2d3f0d6afe99d445084f543b6feaa | F test/lastinsert.test b6a1db3e1ce2d3f0d6afe99d445084f543b6feaa | ||||||
| F test/laststmtchanges.test 07cbdabc52407c29e40abc25050f2434f044a6b1 | F test/laststmtchanges.test 07cbdabc52407c29e40abc25050f2434f044a6b1 | ||||||
| F test/limit.test f833e610ab26c618487c36f62baf6458f9284ce6 | F test/limit.test 270b076f31c5c32f7187de5727e74da4de43e477 | ||||||
| F test/lock.test a19aab9a963273fe61c1058e3d1b648d6a0a2425 | F test/lock.test a19aab9a963273fe61c1058e3d1b648d6a0a2425 | ||||||
| F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f | F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f | ||||||
| F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 | F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 | ||||||
| @@ -270,7 +270,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc | |||||||
| F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 | F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 | ||||||
| F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 | F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 | ||||||
| F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd | F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd | ||||||
| P 6d91a1e91bf0e8b4a0f5f78d079031f3ee69603b | P a9c33a804d572dd9df15be2029637b10e5a65cc4 | ||||||
| R 752d291cdd1da93d3f1d71a58abca891 | R 0ba525d8e5e37833bac3706da6208349 | ||||||
| U danielk1977 | U danielk1977 | ||||||
| Z bc43e9a2df7fa6f5203156118f2ad652 | Z 5a32f92efa7eeaf1966c77064b18ce7a | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| a9c33a804d572dd9df15be2029637b10e5a65cc4 | 515e5033a5482f55e7edb66d69ff3da7e234ff2e | ||||||
| @@ -12,7 +12,7 @@ | |||||||
| ** This file contains routines used for analyzing expressions and | ** This file contains routines used for analyzing expressions and | ||||||
| ** for generating VDBE code that evaluates expressions in SQLite. | ** for generating VDBE code that evaluates expressions in SQLite. | ||||||
| ** | ** | ||||||
| ** $Id: expr.c,v 1.191 2005/02/04 04:07:17 danielk1977 Exp $ | ** $Id: expr.c,v 1.192 2005/02/05 12:48:48 danielk1977 Exp $ | ||||||
| */ | */ | ||||||
| #include "sqliteInt.h" | #include "sqliteInt.h" | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| @@ -511,8 +511,8 @@ Select *sqlite3SelectDup(Select *p){ | |||||||
|   pNew->pOrderBy = sqlite3ExprListDup(p->pOrderBy); |   pNew->pOrderBy = sqlite3ExprListDup(p->pOrderBy); | ||||||
|   pNew->op = p->op; |   pNew->op = p->op; | ||||||
|   pNew->pPrior = sqlite3SelectDup(p->pPrior); |   pNew->pPrior = sqlite3SelectDup(p->pPrior); | ||||||
|   pNew->nLimit = p->nLimit; |   pNew->pLimit = sqlite3ExprDup(p->pLimit); | ||||||
|   pNew->nOffset = p->nOffset; |   pNew->pOffset = sqlite3ExprDup(p->pOffset); | ||||||
|   pNew->iLimit = -1; |   pNew->iLimit = -1; | ||||||
|   pNew->iOffset = -1; |   pNew->iOffset = -1; | ||||||
|   pNew->ppOpenTemp = 0; |   pNew->ppOpenTemp = 0; | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								src/parse.y
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/parse.y
									
									
									
									
									
								
							| @@ -14,7 +14,7 @@ | |||||||
| ** the parser.  Lemon will also generate a header file containing | ** the parser.  Lemon will also generate a header file containing | ||||||
| ** numeric codes for all of the tokens. | ** numeric codes for all of the tokens. | ||||||
| ** | ** | ||||||
| ** @(#) $Id: parse.y,v 1.164 2005/02/04 04:07:17 danielk1977 Exp $ | ** @(#) $Id: parse.y,v 1.165 2005/02/05 12:48:48 danielk1977 Exp $ | ||||||
| */ | */ | ||||||
| %token_prefix TK_ | %token_prefix TK_ | ||||||
| %token_type {Token} | %token_type {Token} | ||||||
| @@ -39,8 +39,8 @@ | |||||||
| ** LIMIT clause of a SELECT statement. | ** LIMIT clause of a SELECT statement. | ||||||
| */ | */ | ||||||
| struct LimitVal { | struct LimitVal { | ||||||
|   int limit;    /* The LIMIT value.  -1 if there is no limit */ |   Expr *pLimit;    /* The LIMIT expression.  NULL if there is no limit */ | ||||||
|   int offset;   /* The OFFSET.  0 if there is none */ |   Expr *pOffset;   /* The OFFSET expression.  NULL if there is none */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -343,7 +343,7 @@ multiselect_op(A) ::= EXCEPT(OP).     {A = @OP;} | |||||||
| %endif // SQLITE_OMIT_COMPOUND_SELECT | %endif // SQLITE_OMIT_COMPOUND_SELECT | ||||||
| oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) | oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) | ||||||
|                  groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { |                  groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { | ||||||
|   A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.limit,L.offset); |   A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); | ||||||
| } | } | ||||||
|  |  | ||||||
| // The "distinct" nonterminal is true (1) if the DISTINCT keyword is | // The "distinct" nonterminal is true (1) if the DISTINCT keyword is | ||||||
| @@ -442,7 +442,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { | |||||||
|   %destructor seltablist_paren {sqlite3SelectDelete($$);} |   %destructor seltablist_paren {sqlite3SelectDelete($$);} | ||||||
|   seltablist_paren(A) ::= select(S).      {A = S;} |   seltablist_paren(A) ::= select(S).      {A = S;} | ||||||
|   seltablist_paren(A) ::= seltablist(F).  { |   seltablist_paren(A) ::= seltablist(F).  { | ||||||
|      A = sqlite3SelectNew(0,F,0,0,0,0,0,-1,0); |      A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0); | ||||||
|   } |   } | ||||||
| %endif // SQLITE_OMIT_SUBQUERY | %endif // SQLITE_OMIT_SUBQUERY | ||||||
|  |  | ||||||
| @@ -513,12 +513,16 @@ having_opt(A) ::= .                {A = 0;} | |||||||
| having_opt(A) ::= HAVING expr(X).  {A = X;} | having_opt(A) ::= HAVING expr(X).  {A = X;} | ||||||
|  |  | ||||||
| %type limit_opt {struct LimitVal} | %type limit_opt {struct LimitVal} | ||||||
| limit_opt(A) ::= .                     {A.limit = -1; A.offset = 0;} | %destructor limit_opt { | ||||||
| limit_opt(A) ::= LIMIT signed(X).      {A.limit = X; A.offset = 0;} |   sqlite3ExprDelete($$.pLimit); | ||||||
| limit_opt(A) ::= LIMIT signed(X) OFFSET signed(Y).  |   sqlite3ExprDelete($$.pOffset); | ||||||
|                                        {A.limit = X; A.offset = Y;} | } | ||||||
| limit_opt(A) ::= LIMIT signed(X) COMMA signed(Y).  | limit_opt(A) ::= .                     {A.pLimit = 0; A.pOffset = 0;} | ||||||
|                                        {A.limit = Y; A.offset = X;} | limit_opt(A) ::= LIMIT expr(X).        {A.pLimit = X; A.pOffset = 0;} | ||||||
|  | limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).  | ||||||
|  |                                        {A.pLimit = X; A.pOffset = Y;} | ||||||
|  | limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).  | ||||||
|  |                                        {A.pOffset = X; A.pLimit = Y;} | ||||||
|  |  | ||||||
| /////////////////////////// The DELETE statement ///////////////////////////// | /////////////////////////// The DELETE statement ///////////////////////////// | ||||||
| // | // | ||||||
| @@ -726,7 +730,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { | |||||||
|   expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] { |   expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] { | ||||||
|     SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z); |     SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z); | ||||||
|     A = sqlite3Expr(TK_IN, X, 0, 0); |     A = sqlite3Expr(TK_IN, X, 0, 0); | ||||||
|     if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,-1,0); |     if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); | ||||||
|     if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); |     if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); | ||||||
|     sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y); |     sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y); | ||||||
|   } |   } | ||||||
|   | |||||||
							
								
								
									
										142
									
								
								src/select.c
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								src/select.c
									
									
									
									
									
								
							| @@ -12,7 +12,7 @@ | |||||||
| ** This file contains C code routines that are called by the parser | ** This file contains C code routines that are called by the parser | ||||||
| ** to handle SELECT statements in SQLite. | ** to handle SELECT statements in SQLite. | ||||||
| ** | ** | ||||||
| ** $Id: select.c,v 1.238 2005/02/04 04:07:17 danielk1977 Exp $ | ** $Id: select.c,v 1.239 2005/02/05 12:48:48 danielk1977 Exp $ | ||||||
| */ | */ | ||||||
| #include "sqliteInt.h" | #include "sqliteInt.h" | ||||||
|  |  | ||||||
| @@ -29,11 +29,12 @@ Select *sqlite3SelectNew( | |||||||
|   Expr *pHaving,        /* the HAVING clause */ |   Expr *pHaving,        /* the HAVING clause */ | ||||||
|   ExprList *pOrderBy,   /* the ORDER BY clause */ |   ExprList *pOrderBy,   /* the ORDER BY clause */ | ||||||
|   int isDistinct,       /* true if the DISTINCT keyword is present */ |   int isDistinct,       /* true if the DISTINCT keyword is present */ | ||||||
|   int nLimit,           /* LIMIT value.  -1 means not used */ |   Expr *pLimit,         /* LIMIT value.  NULL means not used */ | ||||||
|   int nOffset           /* OFFSET value.  0 means no offset */ |   Expr *pOffset         /* OFFSET value.  NULL means no offset */ | ||||||
| ){ | ){ | ||||||
|   Select *pNew; |   Select *pNew; | ||||||
|   pNew = sqliteMalloc( sizeof(*pNew) ); |   pNew = sqliteMalloc( sizeof(*pNew) ); | ||||||
|  |   assert( !pOffset || pLimit );   /* Can't have OFFSET without LIMIT. */ | ||||||
|   if( pNew==0 ){ |   if( pNew==0 ){ | ||||||
|     sqlite3ExprListDelete(pEList); |     sqlite3ExprListDelete(pEList); | ||||||
|     sqlite3SrcListDelete(pSrc); |     sqlite3SrcListDelete(pSrc); | ||||||
| @@ -41,6 +42,8 @@ Select *sqlite3SelectNew( | |||||||
|     sqlite3ExprListDelete(pGroupBy); |     sqlite3ExprListDelete(pGroupBy); | ||||||
|     sqlite3ExprDelete(pHaving); |     sqlite3ExprDelete(pHaving); | ||||||
|     sqlite3ExprListDelete(pOrderBy); |     sqlite3ExprListDelete(pOrderBy); | ||||||
|  |     sqlite3ExprDelete(pLimit); | ||||||
|  |     sqlite3ExprDelete(pOffset); | ||||||
|   }else{ |   }else{ | ||||||
|     if( pEList==0 ){ |     if( pEList==0 ){ | ||||||
|       pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0); |       pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0); | ||||||
| @@ -53,8 +56,8 @@ Select *sqlite3SelectNew( | |||||||
|     pNew->pOrderBy = pOrderBy; |     pNew->pOrderBy = pOrderBy; | ||||||
|     pNew->isDistinct = isDistinct; |     pNew->isDistinct = isDistinct; | ||||||
|     pNew->op = TK_SELECT; |     pNew->op = TK_SELECT; | ||||||
|     pNew->nLimit = nLimit; |     pNew->pLimit = pLimit; | ||||||
|     pNew->nOffset = nOffset; |     pNew->pOffset = pOffset; | ||||||
|     pNew->iLimit = -1; |     pNew->iLimit = -1; | ||||||
|     pNew->iOffset = -1; |     pNew->iOffset = -1; | ||||||
|   } |   } | ||||||
| @@ -308,21 +311,11 @@ void sqlite3SelectDelete(Select *p){ | |||||||
|   sqlite3ExprDelete(p->pHaving); |   sqlite3ExprDelete(p->pHaving); | ||||||
|   sqlite3ExprListDelete(p->pOrderBy); |   sqlite3ExprListDelete(p->pOrderBy); | ||||||
|   sqlite3SelectDelete(p->pPrior); |   sqlite3SelectDelete(p->pPrior); | ||||||
|  |   sqlite3ExprDelete(p->pLimit); | ||||||
|  |   sqlite3ExprDelete(p->pOffset); | ||||||
|   sqliteFree(p); |   sqliteFree(p); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* |  | ||||||
| ** Delete the aggregate information from the parse structure. |  | ||||||
| */ |  | ||||||
| #if 0 |  | ||||||
| static void sqliteAggregateInfoReset(Parse *pParse){ |  | ||||||
|   sqliteFree(pParse->aAgg); |  | ||||||
|   pParse->aAgg = 0; |  | ||||||
|   pParse->nAgg = 0; |  | ||||||
|   pParse->useAgg = 0; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
| ** Insert code into "v" that will push the record on the top of the | ** Insert code into "v" that will push the record on the top of the | ||||||
| ** stack into the sorter. | ** stack into the sorter. | ||||||
| @@ -347,9 +340,10 @@ static void codeLimiter( | |||||||
|   int nPop          /* Number of times to pop stack when jumping */ |   int nPop          /* Number of times to pop stack when jumping */ | ||||||
| ){ | ){ | ||||||
|   if( p->iOffset>=0 ){ |   if( p->iOffset>=0 ){ | ||||||
|     int addr = sqlite3VdbeCurrentAddr(v) + 2; |     int addr = sqlite3VdbeCurrentAddr(v) + 3; | ||||||
|     if( nPop>0 ) addr++; |     if( nPop>0 ) addr++; | ||||||
|     sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, addr); |     sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0); | ||||||
|  |     sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr); | ||||||
|     if( nPop>0 ){ |     if( nPop>0 ){ | ||||||
|       sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); |       sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); | ||||||
|     } |     } | ||||||
| @@ -1274,12 +1268,12 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ | |||||||
|  |  | ||||||
| /* | /* | ||||||
| ** Compute the iLimit and iOffset fields of the SELECT based on the | ** Compute the iLimit and iOffset fields of the SELECT based on the | ||||||
| ** nLimit and nOffset fields.  nLimit and nOffset hold the integers | ** pLimit and pOffset expressions.  nLimit and nOffset hold the expressions | ||||||
| ** that appear in the original SQL statement after the LIMIT and OFFSET | ** that appear in the original SQL statement after the LIMIT and OFFSET | ||||||
| ** keywords.  Or that hold -1 and 0 if those keywords are omitted. | ** keywords.  Or NULL if those keywords are omitted. iLimit and iOffset  | ||||||
| ** iLimit and iOffset are the integer memory register numbers for | ** are the integer memory register numbers for counters used to compute  | ||||||
| ** counters used to compute the limit and offset.  If there is no | ** the limit and offset.  If there is no limit and/or offset, then  | ||||||
| ** limit and/or offset, then iLimit and iOffset are negative. | ** iLimit and iOffset are negative. | ||||||
| ** | ** | ||||||
| ** This routine changes the values if iLimit and iOffset only if | ** This routine changes the values if iLimit and iOffset only if | ||||||
| ** a limit or offset is defined by nLimit and nOffset.  iLimit and | ** a limit or offset is defined by nLimit and nOffset.  iLimit and | ||||||
| @@ -1292,28 +1286,29 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ | |||||||
| */ | */ | ||||||
| static void computeLimitRegisters(Parse *pParse, Select *p){ | static void computeLimitRegisters(Parse *pParse, Select *p){ | ||||||
|   /*  |   /*  | ||||||
|   ** 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 |   ** "LIMIT -1" always shows all rows.  There is some | ||||||
|   ** contraversy about what the correct behavior should be. |   ** contraversy about what the correct behavior should be. | ||||||
|   ** The current implementation interprets "LIMIT 0" to mean |   ** The current implementation interprets "LIMIT 0" to mean | ||||||
|   ** no rows. |   ** no rows. | ||||||
|   */ |   */ | ||||||
|   if( p->nLimit>=0 ){ |   if( p->pLimit ){ | ||||||
|     int iMem = pParse->nMem++; |     int iMem = pParse->nMem++; | ||||||
|     Vdbe *v = sqlite3GetVdbe(pParse); |     Vdbe *v = sqlite3GetVdbe(pParse); | ||||||
|     if( v==0 ) return; |     if( v==0 ) return; | ||||||
|     sqlite3VdbeAddOp(v, OP_Integer, -p->nLimit, 0); |     sqlite3ExprCode(pParse, p->pLimit); | ||||||
|  |     sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); | ||||||
|  |     sqlite3VdbeAddOp(v, OP_Negative, 0, 0); | ||||||
|     sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); |     sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); | ||||||
|     VdbeComment((v, "# LIMIT counter")); |     VdbeComment((v, "# LIMIT counter")); | ||||||
|     p->iLimit = iMem; |     p->iLimit = iMem; | ||||||
|   } |   } | ||||||
|   if( p->nOffset>0 ){ |   if( p->pOffset ){ | ||||||
|     int iMem = pParse->nMem++; |     int iMem = pParse->nMem++; | ||||||
|     Vdbe *v = sqlite3GetVdbe(pParse); |     Vdbe *v = sqlite3GetVdbe(pParse); | ||||||
|     if( v==0 ) return; |     if( v==0 ) return; | ||||||
|     sqlite3VdbeAddOp(v, OP_Integer, -p->nOffset, 0); |     sqlite3ExprCode(pParse, p->pOffset); | ||||||
|  |     sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); | ||||||
|  |     sqlite3VdbeAddOp(v, OP_Negative, 0, 0); | ||||||
|     sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); |     sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); | ||||||
|     VdbeComment((v, "# OFFSET counter")); |     VdbeComment((v, "# OFFSET counter")); | ||||||
|     p->iOffset = iMem; |     p->iOffset = iMem; | ||||||
| @@ -1463,7 +1458,7 @@ static int multiSelect( | |||||||
|     rc = 1; |     rc = 1; | ||||||
|     goto multi_select_end; |     goto multi_select_end; | ||||||
|   } |   } | ||||||
|   if( pPrior->nLimit>=0 || pPrior->nOffset>0 ){ |   if( pPrior->pLimit ){ | ||||||
|     sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before", |     sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before", | ||||||
|       selectOpName(p->op)); |       selectOpName(p->op)); | ||||||
|     rc = 1; |     rc = 1; | ||||||
| @@ -1504,8 +1499,9 @@ static int multiSelect( | |||||||
|   switch( p->op ){ |   switch( p->op ){ | ||||||
|     case TK_ALL: { |     case TK_ALL: { | ||||||
|       if( p->pOrderBy==0 ){ |       if( p->pOrderBy==0 ){ | ||||||
|         pPrior->nLimit = p->nLimit; |         assert( !pPrior->pLimit ); | ||||||
|         pPrior->nOffset = p->nOffset; |         pPrior->pLimit = p->pLimit; | ||||||
|  |         pPrior->pOffset = p->pOffset; | ||||||
|         rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff); |         rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff); | ||||||
|         if( rc ){ |         if( rc ){ | ||||||
|           goto multi_select_end; |           goto multi_select_end; | ||||||
| @@ -1513,8 +1509,8 @@ static int multiSelect( | |||||||
|         p->pPrior = 0; |         p->pPrior = 0; | ||||||
|         p->iLimit = pPrior->iLimit; |         p->iLimit = pPrior->iLimit; | ||||||
|         p->iOffset = pPrior->iOffset; |         p->iOffset = pPrior->iOffset; | ||||||
|         p->nLimit = -1; |         p->pLimit = 0; | ||||||
|         p->nOffset = 0; |         p->pOffset = 0; | ||||||
|         rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff); |         rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff); | ||||||
|         p->pPrior = pPrior; |         p->pPrior = pPrior; | ||||||
|         if( rc ){ |         if( rc ){ | ||||||
| @@ -1529,12 +1525,12 @@ static int multiSelect( | |||||||
|       int unionTab;    /* Cursor number of the temporary table holding result */ |       int unionTab;    /* Cursor number of the temporary table holding result */ | ||||||
|       int op = 0;      /* One of the SRT_ operations to apply to self */ |       int op = 0;      /* One of the SRT_ operations to apply to self */ | ||||||
|       int priorOp;     /* The SRT_ operation to apply to prior selects */ |       int priorOp;     /* The SRT_ operation to apply to prior selects */ | ||||||
|       int nLimit, nOffset; /* Saved values of p->nLimit and p->nOffset */ |       Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */ | ||||||
|       ExprList *pOrderBy;  /* The ORDER BY clause for the right SELECT */ |       ExprList *pOrderBy;     /* The ORDER BY clause for the right SELECT */ | ||||||
|       int addr; |       int addr; | ||||||
|  |  | ||||||
|       priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union; |       priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union; | ||||||
|       if( eDest==priorOp && p->pOrderBy==0 && p->nLimit<0 && p->nOffset==0 ){ |       if( eDest==priorOp && p->pOrderBy==0 && !p->pLimit && !p->pOffset ){ | ||||||
|         /* We can reuse a temporary table generated by a SELECT to our |         /* We can reuse a temporary table generated by a SELECT to our | ||||||
|         ** right. |         ** right. | ||||||
|         */ |         */ | ||||||
| @@ -1580,15 +1576,16 @@ static int multiSelect( | |||||||
|       p->pPrior = 0; |       p->pPrior = 0; | ||||||
|       pOrderBy = p->pOrderBy; |       pOrderBy = p->pOrderBy; | ||||||
|       p->pOrderBy = 0; |       p->pOrderBy = 0; | ||||||
|       nLimit = p->nLimit; |       pLimit = p->pLimit; | ||||||
|       p->nLimit = -1; |       p->pLimit = 0; | ||||||
|       nOffset = p->nOffset; |       pOffset = p->pOffset; | ||||||
|       p->nOffset = 0; |       p->pOffset = 0; | ||||||
|       rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff); |       rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff); | ||||||
|       p->pPrior = pPrior; |       p->pPrior = pPrior; | ||||||
|       p->pOrderBy = pOrderBy; |       p->pOrderBy = pOrderBy; | ||||||
|       p->nLimit = nLimit; |       sqlite3ExprDelete(p->pLimit); | ||||||
|       p->nOffset = nOffset; |       p->pLimit = pLimit; | ||||||
|  |       p->pOffset = pOffset; | ||||||
|       p->iLimit = -1; |       p->iLimit = -1; | ||||||
|       p->iOffset = -1; |       p->iOffset = -1; | ||||||
|       if( rc ){ |       if( rc ){ | ||||||
| @@ -1627,7 +1624,7 @@ static int multiSelect( | |||||||
|     case TK_INTERSECT: { |     case TK_INTERSECT: { | ||||||
|       int tab1, tab2; |       int tab1, tab2; | ||||||
|       int iCont, iBreak, iStart; |       int iCont, iBreak, iStart; | ||||||
|       int nLimit, nOffset; |       Expr *pLimit, *pOffset; | ||||||
|       int addr; |       int addr; | ||||||
|  |  | ||||||
|       /* INTERSECT is different from the others since it requires |       /* INTERSECT is different from the others since it requires | ||||||
| @@ -1669,14 +1666,15 @@ static int multiSelect( | |||||||
|       assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) ); |       assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) ); | ||||||
|       aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab2, 0); |       aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab2, 0); | ||||||
|       p->pPrior = 0; |       p->pPrior = 0; | ||||||
|       nLimit = p->nLimit; |       pLimit = p->pLimit; | ||||||
|       p->nLimit = -1; |       p->pLimit = 0; | ||||||
|       nOffset = p->nOffset; |       pOffset = p->pOffset; | ||||||
|       p->nOffset = 0; |       p->pOffset = 0; | ||||||
|       rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff); |       rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff); | ||||||
|       p->pPrior = pPrior; |       p->pPrior = pPrior; | ||||||
|       p->nLimit = nLimit; |       sqlite3ExprDelete(p->pLimit); | ||||||
|       p->nOffset = nOffset; |       p->pLimit = pLimit; | ||||||
|  |       p->pOffset = pOffset; | ||||||
|       if( rc ){ |       if( rc ){ | ||||||
|         goto multi_select_end; |         goto multi_select_end; | ||||||
|       } |       } | ||||||
| @@ -1959,11 +1957,13 @@ static int flattenSubquery( | |||||||
|   if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; |   if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; | ||||||
|   pSubSrc = pSub->pSrc; |   pSubSrc = pSub->pSrc; | ||||||
|   assert( pSubSrc ); |   assert( pSubSrc ); | ||||||
|  |   if( (pSub->pLimit && p->pLimit) || pSub->pOffset ||  | ||||||
|  |       (pSub->pLimit && isAgg) ) return 0; | ||||||
|   if( pSubSrc->nSrc==0 ) return 0; |   if( pSubSrc->nSrc==0 ) return 0; | ||||||
|   if( (pSub->isDistinct || pSub->nLimit>=0) &&  (pSrc->nSrc>1 || isAgg) ){ |   if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){ | ||||||
|      return 0; |      return 0; | ||||||
|   } |   } | ||||||
|   if( (p->isDistinct || p->nLimit>=0) && subqueryIsAgg ) return 0; |   if( p->isDistinct && subqueryIsAgg ) return 0; | ||||||
|   if( p->pOrderBy && pSub->pOrderBy ) return 0; |   if( p->pOrderBy && pSub->pOrderBy ) return 0; | ||||||
|  |  | ||||||
|   /* Restriction 3:  If the subquery is a join, make sure the subquery is  |   /* Restriction 3:  If the subquery is a join, make sure the subquery is  | ||||||
| @@ -2095,17 +2095,10 @@ static int flattenSubquery( | |||||||
|   */ |   */ | ||||||
|   p->isDistinct = p->isDistinct || pSub->isDistinct; |   p->isDistinct = p->isDistinct || pSub->isDistinct; | ||||||
|  |  | ||||||
|   /* Transfer the limit expression from the subquery to the outer |   if( pSub->pLimit ){ | ||||||
|   ** query. |     p->pLimit = pSub->pLimit; | ||||||
|   */ |     pSub->pLimit = 0; | ||||||
|   if( pSub->nLimit>=0 ){ |  | ||||||
|     if( p->nLimit<0 ){ |  | ||||||
|       p->nLimit = pSub->nLimit; |  | ||||||
|     }else if( p->nLimit+p->nOffset > pSub->nLimit+pSub->nOffset ){ |  | ||||||
|       p->nLimit = pSub->nLimit + pSub->nOffset - p->nOffset; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|   p->nOffset += pSub->nOffset; |  | ||||||
|  |  | ||||||
|   /* Finially, delete what is left of the subquery and return |   /* Finially, delete what is left of the subquery and return | ||||||
|   ** success. |   ** success. | ||||||
| @@ -2330,15 +2323,28 @@ int sqlite3SelectResolve( | |||||||
|     return SQLITE_ERROR; |     return SQLITE_ERROR; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* Set up the local name-context to pass to ExprResolveNames().  */ |   /* Resolve the expressions in the LIMIT and OFFSET clauses. These | ||||||
|   sNC.pNext = pOuterNC; |   ** are not allowed to refer to any names, so pass an empty NameContext. | ||||||
|  |   */ | ||||||
|   sNC.pParse = pParse; |   sNC.pParse = pParse; | ||||||
|   sNC.pSrcList = p->pSrc; |  | ||||||
|   sNC.allowAgg = 1; |  | ||||||
|   sNC.hasAgg = 0; |   sNC.hasAgg = 0; | ||||||
|   sNC.nErr = 0; |   sNC.nErr = 0; | ||||||
|   sNC.nRef = 0; |   sNC.nRef = 0; | ||||||
|   sNC.pEList = 0; |   sNC.pEList = 0; | ||||||
|  |   sNC.allowAgg = 0; | ||||||
|  |   sNC.pSrcList = 0; | ||||||
|  |   sNC.pNext = 0; | ||||||
|  |   if( sqlite3ExprResolveNames(&sNC, p->pLimit) || | ||||||
|  |       sqlite3ExprResolveNames(&sNC, p->pOffset) ){ | ||||||
|  |     return SQLITE_ERROR; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* Set up the local name-context to pass to ExprResolveNames() to | ||||||
|  |   ** resolve the expression-list. | ||||||
|  |   */ | ||||||
|  |   sNC.allowAgg = 1; | ||||||
|  |   sNC.pSrcList = p->pSrc; | ||||||
|  |   sNC.pNext = pOuterNC; | ||||||
|  |  | ||||||
|   /* NameContext.nDepth stores the depth of recursion for this query. For |   /* NameContext.nDepth stores the depth of recursion for this query. For | ||||||
|   ** an outer query (e.g. SELECT * FROM sqlite_master) this is 1. For |   ** an outer query (e.g. SELECT * FROM sqlite_master) this is 1. For | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ | |||||||
| ************************************************************************* | ************************************************************************* | ||||||
| ** Internal interface definitions for SQLite. | ** Internal interface definitions for SQLite. | ||||||
| ** | ** | ||||||
| ** @(#) $Id: sqliteInt.h,v 1.366 2005/02/04 04:07:17 danielk1977 Exp $ | ** @(#) $Id: sqliteInt.h,v 1.367 2005/02/05 12:48:48 danielk1977 Exp $ | ||||||
| */ | */ | ||||||
| #ifndef _SQLITEINT_H_ | #ifndef _SQLITEINT_H_ | ||||||
| #define _SQLITEINT_H_ | #define _SQLITEINT_H_ | ||||||
| @@ -1013,7 +1013,8 @@ struct Select { | |||||||
|   Expr *pHaving;         /* The HAVING clause */ |   Expr *pHaving;         /* The HAVING clause */ | ||||||
|   ExprList *pOrderBy;    /* The ORDER BY clause */ |   ExprList *pOrderBy;    /* The ORDER BY clause */ | ||||||
|   Select *pPrior;        /* Prior select in a compound select statement */ |   Select *pPrior;        /* Prior select in a compound select statement */ | ||||||
|   int nLimit, nOffset;   /* LIMIT and OFFSET values.  -1 means not used */ |   Expr *pLimit;          /* LIMIT expression. NULL means not used. */ | ||||||
|  |   Expr *pOffset;         /* OFFSET expression. NULL means not used. */ | ||||||
|   int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */ |   int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */ | ||||||
|   IdList **ppOpenTemp;   /* OP_OpenTemp addresses used by multi-selects */ |   IdList **ppOpenTemp;   /* OP_OpenTemp addresses used by multi-selects */ | ||||||
|   Fetch *pFetch;         /* If this stmt is part of a FETCH command */ |   Fetch *pFetch;         /* If this stmt is part of a FETCH command */ | ||||||
| @@ -1378,7 +1379,7 @@ void sqlite3AddKeyType(Vdbe*, ExprList*); | |||||||
| void sqlite3AddIdxKeyType(Vdbe*, Index*); | void sqlite3AddIdxKeyType(Vdbe*, Index*); | ||||||
| int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff); | int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff); | ||||||
| Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, | Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, | ||||||
|                         int,int,int); |                         int,Expr*,Expr*); | ||||||
| void sqlite3SelectDelete(Select*); | void sqlite3SelectDelete(Select*); | ||||||
| void sqlite3SelectUnbind(Select*); | void sqlite3SelectUnbind(Select*); | ||||||
| Table *sqlite3SrcListLookup(Parse*, SrcList*); | Table *sqlite3SrcListLookup(Parse*, SrcList*); | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ | |||||||
| ** Most of the code in this file may be omitted by defining the | ** Most of the code in this file may be omitted by defining the | ||||||
| ** SQLITE_OMIT_VACUUM macro. | ** SQLITE_OMIT_VACUUM macro. | ||||||
| ** | ** | ||||||
| ** $Id: vacuum.c,v 1.37 2005/02/03 01:08:20 drh Exp $ | ** $Id: vacuum.c,v 1.38 2005/02/05 12:48:48 danielk1977 Exp $ | ||||||
| */ | */ | ||||||
| #include "sqliteInt.h" | #include "sqliteInt.h" | ||||||
| #include "os.h" | #include "os.h" | ||||||
| @@ -212,7 +212,9 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ | |||||||
|   rc = execExecSql(db,  |   rc = execExecSql(db,  | ||||||
|       "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " |       "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " | ||||||
|       "FROM sqlite_master WHERE name='sqlite_sequence' " |       "FROM sqlite_master WHERE name='sqlite_sequence' " | ||||||
|       "UNION ALL " |   ); | ||||||
|  |   if( rc!=SQLITE_OK ) goto end_of_vacuum; | ||||||
|  |   rc = execExecSql(db,  | ||||||
|       "SELECT 'INSERT INTO vacuum_db.' || quote(name) " |       "SELECT 'INSERT INTO vacuum_db.' || quote(name) " | ||||||
|       "|| ' SELECT * FROM ' || quote(name) || ';' " |       "|| ' SELECT * FROM ' || quote(name) || ';' " | ||||||
|       "FROM sqlite_master WHERE name=='sqlite_sequence';" |       "FROM sqlite_master WHERE name=='sqlite_sequence';" | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								src/vdbe.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/vdbe.c
									
									
									
									
									
								
							| @@ -43,7 +43,7 @@ | |||||||
| ** in this file for details.  If in doubt, do not deviate from existing | ** in this file for details.  If in doubt, do not deviate from existing | ||||||
| ** commenting and indentation practices when changing or adding code. | ** commenting and indentation practices when changing or adding code. | ||||||
| ** | ** | ||||||
| ** $Id: vdbe.c,v 1.452 2005/02/05 06:49:54 danielk1977 Exp $ | ** $Id: vdbe.c,v 1.453 2005/02/05 12:48:48 danielk1977 Exp $ | ||||||
| */ | */ | ||||||
| #include "sqliteInt.h" | #include "sqliteInt.h" | ||||||
| #include "os.h" | #include "os.h" | ||||||
| @@ -4203,7 +4203,7 @@ case OP_MemMax: { | |||||||
| /* Opcode: MemIncr P1 P2 * | /* Opcode: MemIncr P1 P2 * | ||||||
| ** | ** | ||||||
| ** Increment the integer valued memory cell P1 by 1.  If P2 is not zero | ** Increment the integer valued memory cell P1 by 1.  If P2 is not zero | ||||||
| ** and the result after the increment is greater than zero, then jump | ** and the result after the increment is exactly 1, then jump | ||||||
| ** to P2. | ** to P2. | ||||||
| ** | ** | ||||||
| ** This instruction throws an error if the memory cell is not initially | ** This instruction throws an error if the memory cell is not initially | ||||||
| @@ -4216,7 +4216,24 @@ case OP_MemIncr: { | |||||||
|   pMem = &p->aMem[i]; |   pMem = &p->aMem[i]; | ||||||
|   assert( pMem->flags==MEM_Int ); |   assert( pMem->flags==MEM_Int ); | ||||||
|   pMem->i++; |   pMem->i++; | ||||||
|   if( pOp->p2>0 && pMem->i>0 ){ |   if( pOp->p2>0 && pMem->i==1 ){ | ||||||
|  |      pc = pOp->p2 - 1; | ||||||
|  |   } | ||||||
|  |   break; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Opcode: IfMemPos P1 P2 * | ||||||
|  | ** | ||||||
|  | ** If the value of memory cell P1 is 1 or greater, jump to P2. This | ||||||
|  | ** opcode assumes that memory cell P1 holds an integer value. | ||||||
|  | */ | ||||||
|  | case OP_IfMemPos: { | ||||||
|  |   int i = pOp->p1; | ||||||
|  |   Mem *pMem; | ||||||
|  |   assert( i>=0 && i<p->nMem ); | ||||||
|  |   pMem = &p->aMem[i]; | ||||||
|  |   assert( pMem->flags==MEM_Int ); | ||||||
|  |   if( pMem->i>0 ){ | ||||||
|      pc = pOp->p2 - 1; |      pc = pOp->p2 - 1; | ||||||
|   } |   } | ||||||
|   break; |   break; | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
| # This file implements tests to make sure SQLite does not crash or | # This file implements tests to make sure SQLite does not crash or | ||||||
| # segfault if it sees a corrupt database file. | # segfault if it sees a corrupt database file. | ||||||
| # | # | ||||||
| # $Id: corrupt.test,v 1.6 2005/02/05 06:49:55 danielk1977 Exp $ | # $Id: corrupt.test,v 1.7 2005/02/05 12:48:49 danielk1977 Exp $ | ||||||
|  |  | ||||||
| catch {file delete -force test.db} | catch {file delete -force test.db} | ||||||
| catch {file delete -force test.db-journal} | catch {file delete -force test.db-journal} | ||||||
| @@ -121,10 +121,8 @@ do_test corrupt-3.1 { | |||||||
|   db close |   db close | ||||||
|   copy_file test.bu test.db |   copy_file test.bu test.db | ||||||
|   sqlite3 db test.db |   sqlite3 db test.db | ||||||
|   execsql { |   list | ||||||
|     SELECT name, rootpage FROM sqlite_master | } {} | ||||||
|   } |  | ||||||
| } {t1 2 t1i1 85 t2 177} |  | ||||||
| do_test corrupt-3.2 { | do_test corrupt-3.2 { | ||||||
|   set t1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1i1'}] |   set t1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1i1'}] | ||||||
|   set t1i1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1'}] |   set t1i1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1'}] | ||||||
| @@ -135,9 +133,8 @@ do_test corrupt-3.2 { | |||||||
|     UPDATE sqlite_master SET rootpage = $t1i1_r WHERE name = 't1i1'; |     UPDATE sqlite_master SET rootpage = $t1i1_r WHERE name = 't1i1'; | ||||||
|     PRAGMA writable_schema = 0; |     PRAGMA writable_schema = 0; | ||||||
|     PRAGMA schema_version = $cookie; |     PRAGMA schema_version = $cookie; | ||||||
|     SELECT name, rootpage FROM sqlite_master; |  | ||||||
|   " |   " | ||||||
| } {t1 85 t1i1 2 t2 177} | } {} | ||||||
|  |  | ||||||
| # This one tests the case caught by code in checkin [2313]. | # This one tests the case caught by code in checkin [2313]. | ||||||
| do_test corrupt-3.3 { | do_test corrupt-3.3 { | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
| # focus of this file is testing the LIMIT ... OFFSET ... clause | # focus of this file is testing the LIMIT ... OFFSET ... clause | ||||||
| #  of SELECT statements. | #  of SELECT statements. | ||||||
| # | # | ||||||
| # $Id: limit.test,v 1.23 2005/01/21 04:25:47 danielk1977 Exp $ | # $Id: limit.test,v 1.24 2005/02/05 12:48:49 danielk1977 Exp $ | ||||||
|  |  | ||||||
| set testdir [file dirname $argv0] | set testdir [file dirname $argv0] | ||||||
| source $testdir/tester.tcl | source $testdir/tester.tcl | ||||||
| @@ -388,4 +388,41 @@ ifcapable compound { | |||||||
|   } {1 {LIMIT clause should come after UNION not before}} |   } {1 {LIMIT clause should come after UNION not before}} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | # Test LIMIT and OFFSET using SQL variables. | ||||||
|  | do_test limit-10.1 { | ||||||
|  |   set limit 10 | ||||||
|  |   db eval { | ||||||
|  |     SELECT x FROM t1 LIMIT $limit; | ||||||
|  |   } | ||||||
|  | } {31 30 29 28 27 26 25 24 23 22} | ||||||
|  | do_test limit-10.2 { | ||||||
|  |   set limit 5 | ||||||
|  |   set offset 5 | ||||||
|  |   db eval { | ||||||
|  |     SELECT x FROM t1 LIMIT $limit OFFSET $offset; | ||||||
|  |   } | ||||||
|  | } {26 25 24 23 22} | ||||||
|  | do_test limit-10.3 { | ||||||
|  |   set limit -1 | ||||||
|  |   db eval { | ||||||
|  |     SELECT x FROM t1 WHERE x<10 LIMIT $limit; | ||||||
|  |   } | ||||||
|  | } {9 8 7 6 5 4 3 2 1 0} | ||||||
|  | do_test limit-10.4 { | ||||||
|  |   set limit 1.5 | ||||||
|  |   set rc [catch { | ||||||
|  |   db eval { | ||||||
|  |     SELECT x FROM t1 WHERE x<10 LIMIT $limit; | ||||||
|  |   } } msg] | ||||||
|  |   list $rc $msg | ||||||
|  | } {1 {datatype mismatch}} | ||||||
|  | do_test limit-10.5 { | ||||||
|  |   set limit "hello world" | ||||||
|  |   set rc [catch { | ||||||
|  |   db eval { | ||||||
|  |     SELECT x FROM t1 WHERE x<10 LIMIT $limit; | ||||||
|  |   } } msg] | ||||||
|  |   list $rc $msg | ||||||
|  | } {1 {datatype mismatch}} | ||||||
|  |  | ||||||
| finish_test | finish_test | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user