/ Check-in [9d552310]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix for bugs #77 and #80: Rework the LIMIT mechanism to be reentrant and to clean up the VDBE stack properly. (CVS 636)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:9d5523107937e3700c76666fb058694babdd672c
User & Date: drh 2002-06-21 23:01:50
Context
2002-06-22
02:33
An optimization: avoid the use of an intermediate table on UNION ALL if there is no ORDER BY clause. (CVS 637) check-in: 8aa73ce6 user: drh tags: trunk
2002-06-21
23:01
Fix for bugs #77 and #80: Rework the LIMIT mechanism to be reentrant and to clean up the VDBE stack properly. (CVS 636) check-in: 9d552310 user: drh tags: trunk
13:09
Fix for ticket #76: Fix a database corruption that might occur when dropping tables or indices. (CVS 635) check-in: 7936b032 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/select.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
330
331
332
333
334
335
336


337
338
339
340
341
342
343
344
345
346
347
...
479
480
481
482
483
484
485

486

487
488
489
490
491
492
493
494
495
496
....
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
....
1718
1719
1720
1721
1722
1723
1724

1725
1726





1727



1728


1729
1730
1731
1732
1733
1734
1735
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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 $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
  if( v==0 ) return 0;

  /* If there was a LIMIT clause on the SELECT statement, then do the check
  ** to see if this row should be output.
  */
  if( pOrderBy==0 ){
    if( p->nOffset>0 ){


      sqliteVdbeAddOp(v, OP_LimitCk, 1, iContinue);
    }
    if( p->nLimit>0 ){
      sqliteVdbeAddOp(v, OP_LimitCk, 0, iBreak);
    }
  }

  /* Pull the requested columns.
  */
  if( pEList ){
    for(i=0; i<pEList->nExpr; i++){
................................................................................
  int iParm        /* Optional parameter associated with eDest */
){
  int end = sqliteVdbeMakeLabel(v);
  int addr;
  sqliteVdbeAddOp(v, OP_Sort, 0, 0);
  addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end);
  if( p->nOffset>0 ){

    sqliteVdbeAddOp(v, OP_LimitCk, 1, addr);

  }
  if( p->nLimit>0 ){
    sqliteVdbeAddOp(v, OP_LimitCk, 0, end);
  }
  switch( eDest ){
    case SRT_Callback: {
      sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0);
      break;
    }
    case SRT_Table:
................................................................................
  if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
  pSubSrc = pSub->pSrc;
  assert( pSubSrc );
  if( pSubSrc->nSrc!=1 ) return 0;
  if( (pSub->isDistinct || pSub->nLimit>=0) &&  (pSrc->nSrc>1 || isAgg) ){
     return 0;
  }
  if( (p->isDistinct || p->nLimit) && 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.
  */
  iParent = p->base + iFrom;
  iSub = pSub->base;
  substExprList(p->pEList, iParent, pSub->pEList, iSub);
................................................................................
  if( eDest==SRT_Callback ){
    generateColumnNames(pParse, p->base, pTabList, pEList);
  }

  /* Set the limiter
  */
  if( p->nLimit<=0 ){

    p->nOffset = 0;
  }else{





    if( p->nOffset<0 ) p->nOffset = 0;



    sqliteVdbeAddOp(v, OP_Limit, p->nLimit, p->nOffset);


  }

  /* Generate code for all sub-queries in the FROM clause
  */
  for(i=0; i<pTabList->nSrc; i++){
    if( pTabList->a[i].pSelect==0 ) continue;
    sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i,







|







 







>
>
|

|
|







 







>
|
>

|
|







 







|







 







>


>
>
>
>
>
|
>
>
>
|
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
...
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
....
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
....
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.96 2002/06/21 23:01:50 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
................................................................................
  if( v==0 ) return 0;

  /* If there was a LIMIT clause on the SELECT statement, then do the check
  ** to see if this row should be output.
  */
  if( pOrderBy==0 ){
    if( p->nOffset>0 ){
      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_MemIncr, p->nLimit, iBreak);
    }
  }

  /* Pull the requested columns.
  */
  if( pEList ){
    for(i=0; i<pEList->nExpr; i++){
................................................................................
  int iParm        /* Optional parameter associated with eDest */
){
  int end = sqliteVdbeMakeLabel(v);
  int addr;
  sqliteVdbeAddOp(v, OP_Sort, 0, 0);
  addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end);
  if( p->nOffset>0 ){
    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_MemIncr, p->nLimit, end);
  }
  switch( eDest ){
    case SRT_Callback: {
      sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0);
      break;
    }
    case SRT_Table:
................................................................................
  if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
  pSubSrc = pSub->pSrc;
  assert( pSubSrc );
  if( pSubSrc->nSrc!=1 ) return 0;
  if( (pSub->isDistinct || pSub->nLimit>=0) &&  (pSrc->nSrc>1 || isAgg) ){
     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.
  */
  iParent = p->base + iFrom;
  iSub = pSub->base;
  substExprList(p->pEList, iParent, pSub->pEList, iSub);
................................................................................
  if( eDest==SRT_Callback ){
    generateColumnNames(pParse, p->base, pTabList, pEList);
  }

  /* Set the limiter
  */
  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, 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
  */
  for(i=0; i<pTabList->nSrc; i++){
    if( pTabList->a[i].pSelect==0 ) continue;
    sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i,

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
566
567
568
569
570
571
572






573
574
575
576
577
578
579
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.127 2002/06/20 11:36:50 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
** The zSelect field is used when the Select structure must be persistent.
** Normally, the expression tree points to tokens in the original input
** string that encodes the select.  But if the Select structure must live
** longer than its input string (for example when it is used to describe
** 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.






*/
struct Select {
  int isDistinct;        /* True if the DISTINCT keyword is present */
  ExprList *pEList;      /* The fields of the result */
  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */







|







 







>
>
>
>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.128 2002/06/21 23:01:50 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
................................................................................
** The zSelect field is used when the Select structure must be persistent.
** Normally, the expression tree points to tokens in the original input
** string that encodes the select.  But if the Select structure must live
** longer than its input string (for example when it is used to describe
** 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 */
  ExprList *pEList;      /* The fields of the result */
  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
....
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
....
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
....
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
....
4670
4671
4672
4673
4674
4675
4676






















4677
4678
4679
4680
4681
4682
4683
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** 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 $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  int nLineAlloc;     /* Number of spaces allocated for zLine */
  int nMem;           /* Number of memory locations currently allocated */
  Mem *aMem;          /* The memory locations */
  Agg agg;            /* Aggregate information */
  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 */
};

/*
** Create a new virtual database engine.
*/
................................................................................
  "Close",             "MoveTo",            "NewRecno",          "PutIntKey",
  "PutStrKey",         "Distinct",          "Found",             "NotFound",
  "IsUnique",          "NotExists",         "Delete",            "Column",
  "KeyAsData",         "Recno",             "FullKey",           "NullRow",
  "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",         
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
................................................................................
  **
  ** Allocation all the stack space we will ever need.
  */
  NeedStack(p, p->nOp);
  zStack = p->zStack;
  aStack = p->aStack;
  p->tos = -1;
  p->iLimit = 0;
  p->iOffset = 0;

  /* Initialize the aggregrate hash table.
  */
  sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
  p->agg.pSearch = 0;

  rc = SQLITE_OK;
................................................................................
    zStack[tos] = z;
    aStack[tos].n = strlen(z) + 1;
    aStack[tos].flags = STK_Str | STK_Dyn;
  }
  sqliteFree(aRoot);
  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
** into the temporary storage list.
*/
case OP_ListWrite: {
................................................................................
  if( aStack[tos].flags & STK_Str ){
    zStack[tos] = p->aMem[i].z;
    aStack[tos].flags |= STK_Static;
    aStack[tos].flags &= ~STK_Dyn;
  }
  break;
}























/* Opcode: AggReset * P2 *
**
** Reset the aggregator so that it no longer contains any data.
** Future aggregator elements will contain P2 values each.
*/
case OP_AggReset: {







|







 







<
<







 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







 







<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
244
245
246
247
248
249
250


251
252
253
254
255
256
257
....
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
....
1294
1295
1296
1297
1298
1299
1300


1301
1302
1303
1304
1305
1306
1307
....
4059
4060
4061
4062
4063
4064
4065
















































4066
4067
4068
4069
4070
4071
4072
....
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.158 2002/06/21 23:01:50 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
  int nLineAlloc;     /* Number of spaces allocated for zLine */
  int nMem;           /* Number of memory locations currently allocated */
  Mem *aMem;          /* The memory locations */
  Agg agg;            /* Aggregate information */
  int nSet;           /* Number of sets allocated */
  Set *aSet;          /* An array of sets */
  int nCallback;      /* Number of callbacks invoked so far */


  int keylistStackDepth;  /* The size of the "keylist" stack */
  Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
};

/*
** Create a new virtual database engine.
*/
................................................................................
  "Close",             "MoveTo",            "NewRecno",          "PutIntKey",
  "PutStrKey",         "Distinct",          "Found",             "NotFound",
  "IsUnique",          "NotExists",         "Delete",            "Column",
  "KeyAsData",         "Recno",             "FullKey",           "NullRow",
  "Last",              "Rewind",            "Next",              "Destroy",
  "Clear",             "CreateIndex",       "CreateTable",       "IntegrityCk",
  "IdxPut",            "IdxDelete",         "IdxRecno",          "IdxGT",
  "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",        
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
................................................................................
  **
  ** Allocation all the stack space we will ever need.
  */
  NeedStack(p, p->nOp);
  zStack = p->zStack;
  aStack = p->aStack;
  p->tos = -1;



  /* Initialize the aggregrate hash table.
  */
  sqliteHashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
  p->agg.pSearch = 0;

  rc = SQLITE_OK;
................................................................................
    zStack[tos] = z;
    aStack[tos].n = strlen(z) + 1;
    aStack[tos].flags = STK_Str | STK_Dyn;
  }
  sqliteFree(aRoot);
  break;
}

















































/* Opcode: ListWrite * * *
**
** Write the integer on the top of the stack
** into the temporary storage list.
*/
case OP_ListWrite: {
................................................................................
  if( aStack[tos].flags & STK_Str ){
    zStack[tos] = p->aMem[i].z;
    aStack[tos].flags |= STK_Static;
    aStack[tos].flags &= ~STK_Dyn;
  }
  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.
** Future aggregator elements will contain P2 values each.
*/
case OP_AggReset: {

Changes to src/vdbe.h.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** 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 $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
#define OP_IdxDelete          38
#define OP_IdxRecno           39
#define OP_IdxGT              40
#define OP_IdxGE              41

#define OP_MemLoad            42
#define OP_MemStore           43


#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_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_FileOpen           57
#define OP_FileRead           58
#define OP_FileColumn         59

#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_SetInsert          69
#define OP_SetFound           70
#define OP_SetNotFound        71
#define OP_SetFirst           72
#define OP_SetNext            73

#define OP_MakeRecord         74
#define OP_MakeKey            75
#define OP_MakeIdxKey         76
#define OP_IncrKey            77

#define OP_Goto               78
#define OP_If                 79
#define OP_IfNot              80
#define OP_Halt               81

#define OP_ColumnCount        82
#define OP_ColumnName         83
#define OP_Callback           84
#define OP_NullCallback       85

#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_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

/* 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
/* 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_Limit             126
#define OP_LimitCk           127


#define OP_MAX               127

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
void sqliteVdbeCreateCallback(Vdbe*, int*);







|







 







>

|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|

<
<
<
<
|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216




217
218
219
220
221
222
223
224
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** 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.57 2002/06/21 23:01:50 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
#define OP_IdxDelete          38
#define OP_IdxRecno           39
#define OP_IdxGT              40
#define OP_IdxGE              41

#define OP_MemLoad            42
#define OP_MemStore           43
#define OP_MemIncr            44

#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            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           58
#define OP_FileRead           59
#define OP_FileColumn         60

#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          70
#define OP_SetFound           71
#define OP_SetNotFound        72
#define OP_SetFirst           73
#define OP_SetNext            74

#define OP_MakeRecord         75
#define OP_MakeKey            76
#define OP_MakeIdxKey         77
#define OP_IncrKey            78

#define OP_Goto               79
#define OP_If                 80
#define OP_IfNot              81
#define OP_Halt               82

#define OP_ColumnCount        83
#define OP_ColumnName         84
#define OP_Callback           85
#define OP_NullCallback       86

#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                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                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            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_MAX               126

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
void sqliteVdbeCreateCallback(Vdbe*, int*);

Changes to test/limit.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
70
71
72
73
74
75
76




77






































78
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Build some test data
#
set fd [open data1.txt w]
................................................................................
} 2
do_test limit-2.3 {
  execsql {
    SELECT count(*) FROM t1 WHERE rowid IN (SELECT rowid FROM t1 LIMIT 2);
  }
} 2












































finish_test







|







 







>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the LIMIT ... OFFSET ... clause
#  of SELECT statements.
#
# $Id: limit.test,v 1.4 2002/06/21 23:01:51 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Build some test data
#
set fd [open data1.txt w]
................................................................................
} 2
do_test limit-2.3 {
  execsql {
    SELECT count(*) FROM t1 WHERE rowid IN (SELECT rowid FROM t1 LIMIT 2);
  }
} 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

Changes to test/misc1.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
253
254
255
256
257
258
259
260
261
262
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# 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 $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Test the creation and use of tables that have a large number
# of columns.
#
................................................................................
    CREATE TABLE t1(a unique not null, b unique not null);
    INSERT INTO t1 VALUES('a',12345678901234567890);
    INSERT INTO t1 VALUES('b',12345678911234567890);
    INSERT INTO t1 VALUES('c',12345678921234567890);
    SELECT * FROM t1;
  }
} {0 {a 12345678901234567890 b 12345678911234567890 c 12345678921234567890}}


finish_test







|







 








<

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
253
254
255
256
257
258
259
260

261
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc1.test,v 1.9 2002/06/21 23:01:51 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Test the creation and use of tables that have a large number
# of columns.
#
................................................................................
    CREATE TABLE t1(a unique not null, b unique not null);
    INSERT INTO t1 VALUES('a',12345678901234567890);
    INSERT INTO t1 VALUES('b',12345678911234567890);
    INSERT INTO t1 VALUES('c',12345678921234567890);
    SELECT * FROM t1;
  }
} {0 {a 12345678901234567890 b 12345678911234567890 c 12345678921234567890}}


finish_test