From d11d382c995bc35f966e51a988980051b9b1130e Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 21 Jun 2002 23:01:49 +0000 Subject: [PATCH] Fix for bugs #77 and #80: Rework the LIMIT mechanism to be reentrant and to clean up the VDBE stack properly. (CVS 636) FossilOrigin-Name: 9d5523107937e3700c76666fb058694babdd672c --- manifest | 22 +++--- manifest.uuid | 2 +- src/select.c | 35 +++++++--- src/sqliteInt.h | 8 ++- src/vdbe.c | 120 +++++++++++++-------------------- src/vdbe.h | 173 ++++++++++++++++++++++++------------------------ test/limit.test | 44 +++++++++++- test/misc1.test | 3 +- 8 files changed, 218 insertions(+), 189 deletions(-) diff --git a/manifest b/manifest index e1f7bd2dfd..c920d64faa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sfor\sticket\s#76:\sFix\sa\sdatabase\scorruption\sthat\smight\soccur\swhen\ndropping\stables\sor\sindices.\s(CVS\s635) -D 2002-06-21T13:09:17 +C Fix\sfor\sbugs\s#77\sand\s#80:\sRework\sthe\sLIMIT\smechanism\sto\sbe\sreentrant\sand\sto\nclean\sup\sthe\sVDBE\sstack\sproperly.\s(CVS\s636) +D 2002-06-21T23:01:50 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -37,11 +37,11 @@ F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e F src/parse.y 2285d8967d7334d52a2188089e5a881d73ba56f6 F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe -F src/select.c 3eadcde4c74341d8ee7db69948cbcb16df9ae9fc +F src/select.c 346da88a44aef311e932e95239dc0288fdcb10dd F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in 7c8882e352cb70818cfaf9bdb5b1b3bee81ef144 -F src/sqliteInt.h 16ccbf72dd823d5764b475353927410ec272305e +F src/sqliteInt.h f283e5628174d7124c39968442e7adb5b95ea82c F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1 F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf @@ -52,8 +52,8 @@ F src/tokenize.c ac4c46f190346b87da54ec3e2605d160af80c619 F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1 F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95 -F src/vdbe.c c33572f803b853c50c22f84d6dfa6922ec79bf6b -F src/vdbe.h 9b6e632bfa5d52507130f1ae456ef2c01bc0be7e +F src/vdbe.c 774f79483ce809b27c3bdb02afd7295cc3c7acd4 +F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2 F src/where.c 1fdb7aca26c1963eb42615a95e0fc2978eec566a F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 @@ -72,12 +72,12 @@ F test/insert2.test eb8481878a7f52ccb4e3346f87550f5afdd77f76 F test/intpkey.test 69a6a9b41e541f27a2ffcd20264fb35adc3c2680 F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a F test/join.test ea6a4097e4fcebbb16eac7ec819569e759336a74 -F test/limit.test 96b33e108e134b5cc674a660064229d15fa278b9 +F test/limit.test 49b44e027a002c0ba336d723b448f07e05b04466 F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85 F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd F test/minmax.test 29bc5727c3e4c792d5c4745833dd4b505905819e -F test/misc1.test faae0b01cce45a75fe8011b1f462c3ef36fb9bda +F test/misc1.test 18c74cdfa6cc920f1c51827ccb23a442c62caefb F test/misuse.test a3aa2b18a97e4c409a1fcaff5151a4dd804a0162 F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30 F test/null.test 5c2b57307e4b6178aae825eb65ddbee01e76b0fd @@ -137,7 +137,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 2532792a5875f9cc0f7d8eaf90dd49d1f6025ca3 -R 3fe0ffaffb77713981828251190bdd81 +P 7936b0325024c81ed8d4bab192d7350d045ec999 +R d15c924c28dce20794c50e0013aa8eb2 U drh -Z 08d058b9c9d8b8b2fa6e6514672f1243 +Z 7d39bfd0dd2f959041e3d2a9c3cd818e diff --git a/manifest.uuid b/manifest.uuid index 80ff91e261..da81f1e59d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7936b0325024c81ed8d4bab192d7350d045ec999 \ No newline at end of file +9d5523107937e3700c76666fb058694babdd672c \ No newline at end of file diff --git a/src/select.c b/src/select.c index 98ede32fc3..4cd71a2a11 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.95 2002/06/20 03:38:26 drh Exp $ +** $Id: select.c,v 1.96 2002/06/21 23:01:50 drh Exp $ */ #include "sqliteInt.h" @@ -334,10 +334,12 @@ static int selectInnerLoop( */ if( pOrderBy==0 ){ if( p->nOffset>0 ){ - sqliteVdbeAddOp(v, OP_LimitCk, 1, iContinue); + int addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeAddOp(v, OP_MemIncr, p->nOffset, addr+2); + sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); } - if( p->nLimit>0 ){ - sqliteVdbeAddOp(v, OP_LimitCk, 0, iBreak); + if( p->nLimit>=0 ){ + sqliteVdbeAddOp(v, OP_MemIncr, p->nLimit, iBreak); } } @@ -483,10 +485,12 @@ static void generateSortTail( sqliteVdbeAddOp(v, OP_Sort, 0, 0); addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end); if( p->nOffset>0 ){ - sqliteVdbeAddOp(v, OP_LimitCk, 1, addr); + sqliteVdbeAddOp(v, OP_MemIncr, p->nOffset, addr+4); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, addr); } - if( p->nLimit>0 ){ - sqliteVdbeAddOp(v, OP_LimitCk, 0, end); + if( p->nLimit>=0 ){ + sqliteVdbeAddOp(v, OP_MemIncr, p->nLimit, end); } switch( eDest ){ case SRT_Callback: { @@ -1305,7 +1309,7 @@ int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){ if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){ return 0; } - if( (p->isDistinct || p->nLimit) && subqueryIsAgg ) return 0; + if( (p->isDistinct || p->nLimit>=0) && subqueryIsAgg ) return 0; /* If we reach this point, it means flattening is permitted for the ** i-th entry of the FROM clause in the outer query. @@ -1722,10 +1726,21 @@ int sqliteSelect( /* Set the limiter */ if( p->nLimit<=0 ){ + p->nLimit = -1; p->nOffset = 0; }else{ - if( p->nOffset<0 ) p->nOffset = 0; - sqliteVdbeAddOp(v, OP_Limit, p->nLimit, p->nOffset); + int iMem = pParse->nMem++; + sqliteVdbeAddOp(v, OP_Integer, -p->nLimit, 0); + sqliteVdbeAddOp(v, OP_MemStore, iMem, 0); + 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, 0); + p->nOffset = iMem; + } } /* Generate code for all sub-queries in the FROM clause diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 79a44f97ac..ef2d5ed44a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.127 2002/06/20 11:36:50 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.128 2002/06/21 23:01:50 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -570,6 +570,12 @@ struct WhereInfo { ** a VIEW) we have to make a copy of the input string so that the nodes ** of the expression tree will have something to point to. zSelect is used ** to hold that copy. +** +** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. +** If there is a LIMIT clause, the parser sets nLimit to the value of the +** limit and nOffset to the value of the offset (or 0 if there is not +** offset). But later on, nLimit and nOffset become the memory locations +** in the VDBE that record the limit and offset counters. */ struct Select { int isDistinct; /* True if the DISTINCT keyword is present */ diff --git a/src/vdbe.c b/src/vdbe.c index d5ad988510..74978b2414 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.157 2002/06/20 11:36:50 drh Exp $ +** $Id: vdbe.c,v 1.158 2002/06/21 23:01:50 drh Exp $ */ #include "sqliteInt.h" #include @@ -248,8 +248,6 @@ struct Vdbe { int nSet; /* Number of sets allocated */ Set *aSet; /* An array of sets */ int nCallback; /* Number of callbacks invoked so far */ - int iLimit; /* Limit on the number of callbacks remaining */ - int iOffset; /* Offset before beginning to do callbacks */ int keylistStackDepth; /* The size of the "keylist" stack */ Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ }; @@ -1060,28 +1058,28 @@ static char *zOpName[] = { 0, "Last", "Rewind", "Next", "Destroy", "Clear", "CreateIndex", "CreateTable", "IntegrityCk", "IdxPut", "IdxDelete", "IdxRecno", "IdxGT", - "IdxGE", "MemLoad", "MemStore", "ListWrite", - "ListRewind", "ListRead", "ListReset", "ListPush", - "ListPop", "SortPut", "SortMakeRec", "SortMakeKey", - "Sort", "SortNext", "SortCallback", "SortReset", - "FileOpen", "FileRead", "FileColumn", "AggReset", - "AggFocus", "AggNext", "AggSet", "AggGet", - "AggFunc", "AggInit", "AggPush", "AggPop", - "SetInsert", "SetFound", "SetNotFound", "SetFirst", - "SetNext", "MakeRecord", "MakeKey", "MakeIdxKey", - "IncrKey", "Goto", "If", "IfNot", - "Halt", "ColumnCount", "ColumnName", "Callback", - "NullCallback", "Integer", "String", "Pop", - "Dup", "Pull", "Push", "MustBeInt", - "Add", "AddImm", "Subtract", "Multiply", - "Divide", "Remainder", "BitAnd", "BitOr", - "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", - "Eq", "Ne", "Lt", "Le", - "Gt", "Ge", "StrEq", "StrNe", - "StrLt", "StrLe", "StrGt", "StrGe", - "IsNull", "NotNull", "Negative", "And", - "Or", "Not", "Concat", "Noop", - "Function", "Limit", "LimitCk", + "IdxGE", "MemLoad", "MemStore", "MemIncr", + "ListWrite", "ListRewind", "ListRead", "ListReset", + "ListPush", "ListPop", "SortPut", "SortMakeRec", + "SortMakeKey", "Sort", "SortNext", "SortCallback", + "SortReset", "FileOpen", "FileRead", "FileColumn", + "AggReset", "AggFocus", "AggNext", "AggSet", + "AggGet", "AggFunc", "AggInit", "AggPush", + "AggPop", "SetInsert", "SetFound", "SetNotFound", + "SetFirst", "SetNext", "MakeRecord", "MakeKey", + "MakeIdxKey", "IncrKey", "Goto", "If", + "IfNot", "Halt", "ColumnCount", "ColumnName", + "Callback", "NullCallback", "Integer", "String", + "Pop", "Dup", "Pull", "Push", + "MustBeInt", "Add", "AddImm", "Subtract", + "Multiply", "Divide", "Remainder", "BitAnd", + "BitOr", "BitNot", "ShiftLeft", "ShiftRight", + "AbsValue", "Eq", "Ne", "Lt", + "Le", "Gt", "Ge", "StrEq", + "StrNe", "StrLt", "StrLe", "StrGt", + "StrGe", "IsNull", "NotNull", "Negative", + "And", "Or", "Not", "Concat", + "Noop", "Function", }; /* @@ -1300,8 +1298,6 @@ int sqliteVdbeExec( zStack = p->zStack; aStack = p->aStack; p->tos = -1; - p->iLimit = 0; - p->iOffset = 0; /* Initialize the aggregrate hash table. */ @@ -4068,54 +4064,6 @@ case OP_IntegrityCk: { break; } -/* Opcode: Limit P1 P2 * -** -** Set a limit and offset on callbacks. P1 is the limit and P2 is -** the offset. If the offset counter is positive, no callbacks are -** invoked but instead the counter is decremented. Once the offset -** counter reaches zero, callbacks are invoked and the limit -** counter is decremented. When the limit counter reaches zero, -** the OP_Callback or OP_SortCallback instruction executes a jump -** that should end the query. -** -** This opcode is used to implement the "LIMIT x OFFSET y" clause -** of a SELECT statement. -*/ -case OP_Limit: { - p->iLimit = pOp->p1; - p->iOffset = pOp->p2; - break; -} - -/* Opcode: LimitCk P1 P2 * -** -** If P1 is 1, then check to see if the offset counter (set by the -** P2 argument of OP_Limit) is positive. If the offset counter is -** positive then decrement the counter and jump immediately to P2. -** Otherwise fall straight through. -** -** If P1 is 0, then check the value of the limit counter (set by the -** P1 argument of OP_Limit). If the limit counter is negative or -** zero then jump immedately to P2. Otherwise decrement the limit -** counter and fall through. -*/ -case OP_LimitCk: { - if( pOp->p1 ){ - if( p->iOffset ){ - p->iOffset--; - pc = pOp->p2 - 1; - } - }else{ - if( p->iLimit>0 ){ - p->iLimit--; - }else{ - pc = pOp->p2 - 1; - } - } - break; -} - - /* Opcode: ListWrite * * * ** ** Write the integer on the top of the stack @@ -4675,6 +4623,28 @@ case OP_MemLoad: { break; } +/* Opcode: MemIncr P1 P2 * +** +** 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 +** to P2. +** +** This instruction throws an error if the memory cell is not initially +** an integer. +*/ +case OP_MemIncr: { + int i = pOp->p1; + Mem *pMem; + VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; ) + pMem = &p->aMem[i]; + VERIFY( if( pMem->s.flags != STK_Int ) goto bad_instruction; ) + pMem->s.i++; + if( pOp->p2>0 && pMem->s.i>0 ){ + pc = pOp->p2 - 1; + } + break; +} + /* Opcode: AggReset * P2 * ** ** Reset the aggregator so that it no longer contains any data. diff --git a/src/vdbe.h b/src/vdbe.h index 91b34f24dc..833f71dd12 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.56 2002/06/20 11:36:50 drh Exp $ +** $Id: vdbe.h,v 1.57 2002/06/21 23:01:50 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -116,108 +116,105 @@ typedef struct VdbeOp VdbeOp; #define OP_MemLoad 42 #define OP_MemStore 43 +#define OP_MemIncr 44 -#define OP_ListWrite 44 -#define OP_ListRewind 45 -#define OP_ListRead 46 -#define OP_ListReset 47 -#define OP_ListPush 48 -#define OP_ListPop 49 +#define OP_ListWrite 45 +#define OP_ListRewind 46 +#define OP_ListRead 47 +#define OP_ListReset 48 +#define OP_ListPush 49 +#define OP_ListPop 50 -#define OP_SortPut 50 -#define OP_SortMakeRec 51 -#define OP_SortMakeKey 52 -#define OP_Sort 53 -#define OP_SortNext 54 -#define OP_SortCallback 55 -#define OP_SortReset 56 +#define OP_SortPut 51 +#define OP_SortMakeRec 52 +#define OP_SortMakeKey 53 +#define OP_Sort 54 +#define OP_SortNext 55 +#define OP_SortCallback 56 +#define OP_SortReset 57 -#define OP_FileOpen 57 -#define OP_FileRead 58 -#define OP_FileColumn 59 +#define OP_FileOpen 58 +#define OP_FileRead 59 +#define OP_FileColumn 60 -#define OP_AggReset 60 -#define OP_AggFocus 61 -#define OP_AggNext 62 -#define OP_AggSet 63 -#define OP_AggGet 64 -#define OP_AggFunc 65 -#define OP_AggInit 66 -#define OP_AggPush 67 -#define OP_AggPop 68 +#define OP_AggReset 61 +#define OP_AggFocus 62 +#define OP_AggNext 63 +#define OP_AggSet 64 +#define OP_AggGet 65 +#define OP_AggFunc 66 +#define OP_AggInit 67 +#define OP_AggPush 68 +#define OP_AggPop 69 -#define OP_SetInsert 69 -#define OP_SetFound 70 -#define OP_SetNotFound 71 -#define OP_SetFirst 72 -#define OP_SetNext 73 +#define OP_SetInsert 70 +#define OP_SetFound 71 +#define OP_SetNotFound 72 +#define OP_SetFirst 73 +#define OP_SetNext 74 -#define OP_MakeRecord 74 -#define OP_MakeKey 75 -#define OP_MakeIdxKey 76 -#define OP_IncrKey 77 +#define OP_MakeRecord 75 +#define OP_MakeKey 76 +#define OP_MakeIdxKey 77 +#define OP_IncrKey 78 -#define OP_Goto 78 -#define OP_If 79 -#define OP_IfNot 80 -#define OP_Halt 81 +#define OP_Goto 79 +#define OP_If 80 +#define OP_IfNot 81 +#define OP_Halt 82 -#define OP_ColumnCount 82 -#define OP_ColumnName 83 -#define OP_Callback 84 -#define OP_NullCallback 85 +#define OP_ColumnCount 83 +#define OP_ColumnName 84 +#define OP_Callback 85 +#define OP_NullCallback 86 -#define OP_Integer 86 -#define OP_String 87 -#define OP_Pop 88 -#define OP_Dup 89 -#define OP_Pull 90 -#define OP_Push 91 -#define OP_MustBeInt 92 +#define OP_Integer 87 +#define OP_String 88 +#define OP_Pop 89 +#define OP_Dup 90 +#define OP_Pull 91 +#define OP_Push 92 +#define OP_MustBeInt 93 -#define OP_Add 93 -#define OP_AddImm 94 -#define OP_Subtract 95 -#define OP_Multiply 96 -#define OP_Divide 97 -#define OP_Remainder 98 -#define OP_BitAnd 99 -#define OP_BitOr 100 -#define OP_BitNot 101 -#define OP_ShiftLeft 102 -#define OP_ShiftRight 103 -#define OP_AbsValue 104 +#define OP_Add 94 +#define OP_AddImm 95 +#define OP_Subtract 96 +#define OP_Multiply 97 +#define OP_Divide 98 +#define OP_Remainder 99 +#define OP_BitAnd 100 +#define OP_BitOr 101 +#define OP_BitNot 102 +#define OP_ShiftLeft 103 +#define OP_ShiftRight 104 +#define OP_AbsValue 105 /* Note: The code generator assumes that OP_XX+6==OP_StrXX */ -#define OP_Eq 105 -#define OP_Ne 106 -#define OP_Lt 107 -#define OP_Le 108 -#define OP_Gt 109 -#define OP_Ge 110 -#define OP_StrEq 111 -#define OP_StrNe 112 -#define OP_StrLt 113 -#define OP_StrLe 114 -#define OP_StrGt 115 -#define OP_StrGe 116 +#define OP_Eq 106 +#define OP_Ne 107 +#define OP_Lt 108 +#define OP_Le 109 +#define OP_Gt 110 +#define OP_Ge 111 +#define OP_StrEq 112 +#define OP_StrNe 113 +#define OP_StrLt 114 +#define OP_StrLe 115 +#define OP_StrGt 116 +#define OP_StrGe 117 /* Note: the code generator assumes that OP_XX+6==OP_StrXX */ -#define OP_IsNull 117 -#define OP_NotNull 118 -#define OP_Negative 119 -#define OP_And 120 -#define OP_Or 121 -#define OP_Not 122 -#define OP_Concat 123 -#define OP_Noop 124 -#define OP_Function 125 +#define OP_IsNull 118 +#define OP_NotNull 119 +#define OP_Negative 120 +#define OP_And 121 +#define OP_Or 122 +#define OP_Not 123 +#define OP_Concat 124 +#define OP_Noop 125 +#define OP_Function 126 -#define OP_Limit 126 -#define OP_LimitCk 127 - - -#define OP_MAX 127 +#define OP_MAX 126 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/test/limit.test b/test/limit.test index 60221c497d..bc157fdf66 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.3 2002/06/14 22:38:43 drh Exp $ +# $Id: limit.test,v 1.4 2002/06/21 23:01:51 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -74,5 +74,47 @@ do_test limit-2.3 { } } 2 +do_test limit-3.1 { + execsql { + SELECT z FROM (SELECT y*10+x AS z FROM t1 ORDER BY x LIMIT 10) + ORDER BY z LIMIT 5; + } +} {50 51 52 53 54} + +do_test limit-4.1 { + execsql { + BEGIN; + CREATE TABLE t3 AS SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; + END; + SELECT count(*) FROM t3; + } +} {10240} +do_test limit-4.2 { + execsql { + SELECT x FROM t3 LIMIT 2 OFFSET 10000 + } +} {10001 10002} +do_test limit-4.3 { + execsql { + CREATE TABLE t4 AS SELECT x, + 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || + 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || + 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || + 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || + 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x AS y + FROM t3 LIMIT 1000; + SELECT x FROM t4 ORDER BY y DESC LIMIT 1 OFFSET 999; + } +} {1} finish_test diff --git a/test/misc1.test b/test/misc1.test index 2ded00d6d4..051b7b3025 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc1.test,v 1.8 2002/06/09 01:16:01 drh Exp $ +# $Id: misc1.test,v 1.9 2002/06/21 23:01:51 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -258,5 +258,4 @@ do_test misc1-9.1 { } } {0 {a 12345678901234567890 b 12345678911234567890 c 12345678921234567890}} - finish_test