SQLite

Check-in [c602603e7c]
Login

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

Overview
Comment:Fix for ticket #136: Added the OP_RenameCursor VDBE instruction and used it to make cursor numbers right on nested subqueries. Also added OP_Gosub and OP_Return but have not actually used them for anything yet. (CVS 727)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c602603e7cd8dc5c8bb9db2748eacab650de5bf0
User & Date: drh 2002-08-25 19:20:40.000
Context
2002-08-25
20:11
Documentation updates prior to the releae of 2.7.0. (CVS 728) (check-in: e2d95f85a3 user: drh tags: trunk)
19:20
Fix for ticket #136: Added the OP_RenameCursor VDBE instruction and used it to make cursor numbers right on nested subqueries. Also added OP_Gosub and OP_Return but have not actually used them for anything yet. (CVS 727) (check-in: c602603e7c user: drh tags: trunk)
18:29
Fix the memory leak introduced by check-in (725). (CVS 726) (check-in: b957dafc26 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/select.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    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.109 2002/08/25 18:29:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    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.110 2002/08/25 19:20:40 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
1399
1400
1401
1402
1403
1404
1405
1406






1407
1408
1409
1410
1411
1412
1413
**
** If flattening is not attempted, this routine is a no-op and return 0.
** If flattening is attempted this routine returns 1.
**
** All of the expression analysis must occur on both the outer query and
** the subquery before this routine runs.
*/
int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){






  Select *pSub;       /* The inner query or "subquery" */
  SrcList *pSrc;      /* The FROM clause of the outer query */
  SrcList *pSubSrc;   /* The FROM clause of the subquery */
  ExprList *pList;    /* The result set of the outer query */
  int i;
  int iParent, iSub;
  Expr *pWhere;







|
>
>
>
>
>
>







1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
**
** If flattening is not attempted, this routine is a no-op and return 0.
** If flattening is attempted this routine returns 1.
**
** All of the expression analysis must occur on both the outer query and
** the subquery before this routine runs.
*/
static int flattenSubquery(
  Parse *pParse,       /* The parsing context */
  Select *p,           /* The parent or outer SELECT statement */
  int iFrom,           /* Index in p->pSrc->a[] of the inner subquery */
  int isAgg,           /* True if outer SELECT uses aggregate functions */
  int subqueryIsAgg    /* True if the subquery uses aggregate functions */
){
  Select *pSub;       /* The inner query or "subquery" */
  SrcList *pSrc;      /* The FROM clause of the outer query */
  SrcList *pSubSrc;   /* The FROM clause of the subquery */
  ExprList *pList;    /* The result set of the outer query */
  int i;
  int iParent, iSub;
  Expr *pWhere;
1482
1483
1484
1485
1486
1487
1488

1489
1490
1491
1492
1493
1494
1495
1496














1497
1498
1499
1500
1501
1502
1503
  }else{
    substExpr(p->pWhere, iParent, pSub->pEList, iSub);
    if( pWhere ){
      p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0);
    }
  }
  p->isDistinct = p->isDistinct || pSub->isDistinct;

  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;














  if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
    sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
  }
  pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab;
  pSubSrc->a[0].pTab = 0;
  assert( pSrc->a[iFrom].pSelect==pSub );
  pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect;







>








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







1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
  }else{
    substExpr(p->pWhere, iParent, pSub->pEList, iSub);
    if( pWhere ){
      p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0);
    }
  }
  p->isDistinct = p->isDistinct || pSub->isDistinct;

  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;

  /* If the subquery contains subqueries of its own, that were not
  ** flattened, then code will have already been generated to put
  ** the results of those sub-subqueries into VDBE cursors relative
  ** to the subquery.  We must translate the cursor number into values
  ** suitable for use by the outer query.
  */
  for(i=0; i<pSubSrc->nSrc; i++){
    Vdbe *v;
    if( pSubSrc->a[i].pSelect==0 ) continue;
    v = sqliteGetVdbe(pParse);
    sqliteVdbeAddOp(v, OP_RenameCursor, pSub->base+i, p->base+i);
  }

  if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
    sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
  }
  pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab;
  pSubSrc->a[0].pTab = 0;
  assert( pSrc->a[iFrom].pSelect==pSub );
  pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect;
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
    isDistinct = p->isDistinct;
  }

  /* Check to see if this is a subquery that can be "flattened" into its parent.
  ** If flattening is a possiblity, do so and return immediately.  
  */
  if( pParent && pParentAgg &&
      flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){
    if( isAgg ) *pParentAgg = 1;
    return rc;
  }

  /* If the output is destined for a temporary table, open that table.
  */
  if( eDest==SRT_TempTable ){







|







1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
    isDistinct = p->isDistinct;
  }

  /* Check to see if this is a subquery that can be "flattened" into its parent.
  ** If flattening is a possiblity, do so and return immediately.  
  */
  if( pParent && pParentAgg &&
      flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
    if( isAgg ) *pParentAgg = 1;
    return rc;
  }

  /* If the output is destined for a temporary table, open that table.
  */
  if( eDest==SRT_TempTable ){
Changes to src/trigger.c.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
** Delete a linked list of TriggerStep structures.
*/
static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
  while( pTriggerStep ){
    TriggerStep * pTmp = pTriggerStep;
    pTriggerStep = pTriggerStep->pNext;

    if( pTmp->target.dyn ) sqliteFree(pTmp->target.z);
    sqliteExprDelete(pTmp->pWhere);
    sqliteExprListDelete(pTmp->pExprList);
    sqliteSelectDelete(pTmp->pSelect);
    sqliteIdListDelete(pTmp->pIdList);

    sqliteFree(pTmp);
  }







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
** Delete a linked list of TriggerStep structures.
*/
static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
  while( pTriggerStep ){
    TriggerStep * pTmp = pTriggerStep;
    pTriggerStep = pTriggerStep->pNext;

    if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
    sqliteExprDelete(pTmp->pWhere);
    sqliteExprListDelete(pTmp->pExprList);
    sqliteSelectDelete(pTmp->pSelect);
    sqliteIdListDelete(pTmp->pIdList);

    sqliteFree(pTmp);
  }
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  return pTriggerStep;
}

/* 
** Recursively delete a Trigger structure
*/
void sqliteDeleteTrigger(Trigger *pTrigger){
  TriggerStep *pTriggerStep;

  sqliteDeleteTriggerStep(pTrigger->step_list);
  sqliteFree(pTrigger->name);
  sqliteFree(pTrigger->table);
  sqliteExprDelete(pTrigger->pWhen);
  sqliteIdListDelete(pTrigger->pColumns);
  sqliteFree(pTrigger);
}







<
<







308
309
310
311
312
313
314


315
316
317
318
319
320
321
  return pTriggerStep;
}

/* 
** Recursively delete a Trigger structure
*/
void sqliteDeleteTrigger(Trigger *pTrigger){


  sqliteDeleteTriggerStep(pTrigger->step_list);
  sqliteFree(pTrigger->name);
  sqliteFree(pTrigger->table);
  sqliteExprDelete(pTrigger->pWhen);
  sqliteIdListDelete(pTrigger->pColumns);
  sqliteFree(pTrigger);
}
Changes to src/vdbe.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** 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.170 2002/08/25 18:29:13 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







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** 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.171 2002/08/25 19:20:40 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
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
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
** "opNames.awk" awk script which is part of the source tree to regenerate
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
  "Transaction",       "Checkpoint",        "Commit",            "Rollback",
  "ReadCookie",        "SetCookie",         "VerifyCookie",      "Open",
  "OpenTemp",          "OpenWrite",         "OpenAux",           "OpenWrAux",
  "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.







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







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
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
** "opNames.awk" awk script which is part of the source tree to regenerate
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
  "Transaction",       "Checkpoint",        "Commit",            "Rollback",
  "ReadCookie",        "SetCookie",         "VerifyCookie",      "Open",
  "OpenTemp",          "OpenWrite",         "OpenAux",           "OpenWrAux",
  "RenameCursor",      "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",              "Gosub",
  "Return",            "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.
1297
1298
1299
1300
1301
1302
1303



















1304
1305
1306
1307
1308
1309
1310
  }
  if( pOut==0 ) pOut = stdout;
  fprintf(pOut,"%4d %-12s %4d %4d %s\n",
      pc, zOpName[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");
  fflush(pOut);
}
#endif




















/*
** Execute the program in the VDBE.
**
** If an error occurs, an error message is written to memory obtained
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
** The return parameter is the number of errors.







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







1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
  }
  if( pOut==0 ) pOut = stdout;
  fprintf(pOut,"%4d %-12s %4d %4d %s\n",
      pc, zOpName[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : "");
  fflush(pOut);
}
#endif

/*
** Make sure there is space in the Vdbe structure to hold at least
** mxCursor cursors.  If there is not currently enough space, then
** allocate more.
**
** If a memory allocation error occurs, return 1.  Return 0 if
** everything works.
*/
static int expandCursorArraySize(Vdbe *p, int mxCursor){
  if( mxCursor>=p->nCursor ){
    Cursor *aCsr = sqliteRealloc( p->aCsr, (mxCursor+1)*sizeof(Cursor) );
    if( aCsr==0 ) return 1;
    p->aCsr = aCsr;
    memset(&p->aCsr[p->nCursor], 0, sizeof(Cursor)*(mxCursor+1-p->nCursor));
    p->nCursor = mxCursor+1;
  }
  return 0;
}

/*
** Execute the program in the VDBE.
**
** If an error occurs, an error message is written to memory obtained
** from sqliteMalloc() and *pzErrMsg is made to point to that memory.
** The return parameter is the number of errors.
1343
1344
1345
1346
1347
1348
1349


1350
1351
1352
1353
1354
1355
1356
  sqlite *db = p->db;        /* The database */
  char **zStack;             /* Text stack */
  Stack *aStack;             /* Additional stack information */
  unsigned uniqueCnt = 0;     /* Used by OP_MakeRecord when P2!=0 */
  int errorAction = OE_Abort; /* Recovery action to do in case of an error */
  int undoTransOnError = 0;   /* If error, either ROLLBACK or COMMIT */
  char zBuf[100];             /* Space to sprintf() an integer */




  /* No instruction ever pushes more than a single element onto the
  ** stack.  And the stack never grows on successive executions of the
  ** same loop.  So the total number of instructions is an upper bound
  ** on the maximum stack depth required.
  **







>
>







1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
  sqlite *db = p->db;        /* The database */
  char **zStack;             /* Text stack */
  Stack *aStack;             /* Additional stack information */
  unsigned uniqueCnt = 0;     /* Used by OP_MakeRecord when P2!=0 */
  int errorAction = OE_Abort; /* Recovery action to do in case of an error */
  int undoTransOnError = 0;   /* If error, either ROLLBACK or COMMIT */
  char zBuf[100];             /* Space to sprintf() an integer */
  int returnStack[100];     /* Return address stack for OP_Gosub & OP_Return */
  int returnDepth = 0;      /* Next unused element in returnStack[] */


  /* No instruction ever pushes more than a single element onto the
  ** stack.  And the stack never grows on successive executions of the
  ** same loop.  So the total number of instructions is an upper bound
  ** on the maximum stack depth required.
  **
1417
1418
1419
1420
1421
1422
1423






































1424
1425
1426
1427
1428
1429
1430
** the one at index P2 from the beginning of
** the program.
*/
case OP_Goto: {
  pc = pOp->p2 - 1;
  break;
}







































/* Opcode:  Halt P1 P2 *
**
** Exit immediately.  All open cursors, Lists, Sorts, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite_exec().  For a normal







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







1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
** the one at index P2 from the beginning of
** the program.
*/
case OP_Goto: {
  pc = pOp->p2 - 1;
  break;
}

/* Opcode:  Gosub * P2 *
**
** Push the current address plus 1 onto the return address stack
** and then jump to address P2.
**
** The return address stack is of limited depth.  If too many
** OP_Gosub operations occur without intervening OP_Returns, then
** the return address stack will fill up and processing will abort
** with a fatal error.
*/
case OP_Gosub: {
  if( returnDepth>=sizeof(returnStack)/sizeof(returnStack[0]) ){
    sqliteSetString(pzErrMsg, "return address stack overflow", 0);
    rc = SQLITE_INTERNAL;
    goto cleanup;
  }
  returnStack[returnDepth++] = pc+1;
  pc = pOp->p2 - 1;
  break;
}

/* Opcode:  Return * * *
**
** Jump immediately to the next instruction after the last unreturned
** OP_Gosub.  If an OP_Return has occurred for all OP_Gosubs, then
** processing aborts with a fatal error.
*/
case OP_Return: {
  if( returnDepth<=0 ){
    sqliteSetString(pzErrMsg, "return address stack underflow", 0);
    rc = SQLITE_INTERNAL;
    goto cleanup;
  }
  returnDepth--;
  pc = returnStack[returnDepth] - 1;
  break;
}

/* Opcode:  Halt P1 P2 *
**
** Exit immediately.  All open cursors, Lists, Sorts, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite_exec().  For a normal
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
    if( p2<2 ){
      sqliteSetString(pzErrMsg, "root page number less than 2", 0);
      rc = SQLITE_INTERNAL;
      goto cleanup;
    }
  }
  VERIFY( if( i<0 ) goto bad_instruction; )
  if( i>=p->nCursor ){
    int j;
    Cursor *aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
    if( aCsr==0 ) goto no_mem;
    p->aCsr = aCsr;
    for(j=p->nCursor; j<=i; j++){
      memset(&p->aCsr[j], 0, sizeof(Cursor));
    }
    p->nCursor = i+1;
  }
  cleanupCursor(&p->aCsr[i]);
  memset(&p->aCsr[i], 0, sizeof(Cursor));
  p->aCsr[i].nullRow = 1;
  if( pX==0 ) break;
  do{
    rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
    switch( rc ){







<
<
<
|
<
<
<
<
<
<







3161
3162
3163
3164
3165
3166
3167



3168






3169
3170
3171
3172
3173
3174
3175
    if( p2<2 ){
      sqliteSetString(pzErrMsg, "root page number less than 2", 0);
      rc = SQLITE_INTERNAL;
      goto cleanup;
    }
  }
  VERIFY( if( i<0 ) goto bad_instruction; )



  if( expandCursorArraySize(p, i) ) goto no_mem;






  cleanupCursor(&p->aCsr[i]);
  memset(&p->aCsr[i], 0, sizeof(Cursor));
  p->aCsr[i].nullRow = 1;
  if( pX==0 ) break;
  do{
    rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
    switch( rc ){
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
** whereas "Temporary" in the context of CREATE TABLE means for the duration
** of the connection to the database.  Same word; different meanings.
*/
case OP_OpenTemp: {
  int i = pOp->p1;
  Cursor *pCx;
  VERIFY( if( i<0 ) goto bad_instruction; )
  if( i>=p->nCursor ){
    int j;
    Cursor *aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
    if( aCsr==0 ){ goto no_mem; }
    p->aCsr = aCsr;
    for(j=p->nCursor; j<=i; j++){
      memset(&p->aCsr[j], 0, sizeof(Cursor));
    }
    p->nCursor = i+1;
  }
  pCx = &p->aCsr[i];
  cleanupCursor(pCx);
  memset(pCx, 0, sizeof(*pCx));
  pCx->nullRow = 1;
  rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
  if( rc==SQLITE_OK ){
    rc = sqliteBtreeBeginTrans(pCx->pBt);







<
<
<
|
<
<
<
<
<
<







3210
3211
3212
3213
3214
3215
3216



3217






3218
3219
3220
3221
3222
3223
3224
** whereas "Temporary" in the context of CREATE TABLE means for the duration
** of the connection to the database.  Same word; different meanings.
*/
case OP_OpenTemp: {
  int i = pOp->p1;
  Cursor *pCx;
  VERIFY( if( i<0 ) goto bad_instruction; )



  if( expandCursorArraySize(p, i) ) goto no_mem;






  pCx = &p->aCsr[i];
  cleanupCursor(pCx);
  memset(pCx, 0, sizeof(*pCx));
  pCx->nullRow = 1;
  rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
  if( rc==SQLITE_OK ){
    rc = sqliteBtreeBeginTrans(pCx->pBt);
3190
3191
3192
3193
3194
3195
3196





















3197
3198
3199
3200
3201
3202
3203
      }
    }else{
      rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
    }
  }
  break;
}






















/* Opcode: Close P1 * *
**
** Close a cursor previously opened as P1.  If P1 is not
** currently open, this instruction is a no-op.
*/
case OP_Close: {







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







3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
      }
    }else{
      rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
    }
  }
  break;
}

/*
** Opcode: RenameCursor P1 P2 *
**
** Rename cursor number P1 as cursor number P2.  If P2 was previously
** opened is is closed before the renaming occurs.
*/
case OP_RenameCursor: {
  int from = pOp->p1;
  int to = pOp->p2;
  VERIFY( if( from<0 || to<0 ) goto bad_instruction; )
  if( to<p->nCursor && p->aCsr[to].pCursor ){
    cleanupCursor(&p->aCsr[to]);
  }
  expandCursorArraySize(p, to);
  if( from<p->nCursor ){
    memcpy(&p->aCsr[to], &p->aCsr[from], sizeof(p->aCsr[0]));
    memset(&p->aCsr[from], 0, sizeof(p->aCsr[0]));
  }
  break;
}

/* Opcode: Close P1 * *
**
** Close a cursor previously opened as P1.  If P1 is not
** currently open, this instruction is a no-op.
*/
case OP_Close: {
Changes to src/vdbe.h.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*************************************************************************
** 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







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*************************************************************************
** 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.58 2002/08/25 19:20:42 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
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
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
#define OP_VerifyCookie        7

#define OP_Open                8
#define OP_OpenTemp            9
#define OP_OpenWrite          10
#define OP_OpenAux            11
#define OP_OpenWrAux          12

#define OP_Close              13
#define OP_MoveTo             14
#define OP_NewRecno           15
#define OP_PutIntKey          16
#define OP_PutStrKey          17
#define OP_Distinct           18
#define OP_Found              19
#define OP_NotFound           20
#define OP_IsUnique           21
#define OP_NotExists          22
#define OP_Delete             23
#define OP_Column             24
#define OP_KeyAsData          25
#define OP_Recno              26
#define OP_FullKey            27
#define OP_NullRow            28
#define OP_Last               29
#define OP_Rewind             30
#define OP_Next               31

#define OP_Destroy            32
#define OP_Clear              33
#define OP_CreateIndex        34
#define OP_CreateTable        35
#define OP_IntegrityCk        36

#define OP_IdxPut             37
#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*);







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

|
|
|
|
|

|
|
|
|
|

|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|
|

|
|
|
|

|
|
|
|
>
>

|
|
|
|

|
|
|
|
|
|
|

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

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

|
|
|
|
|
|
|
|
|

|







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
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
#define OP_VerifyCookie        7

#define OP_Open                8
#define OP_OpenTemp            9
#define OP_OpenWrite          10
#define OP_OpenAux            11
#define OP_OpenWrAux          12
#define OP_RenameCursor       13
#define OP_Close              14
#define OP_MoveTo             15
#define OP_NewRecno           16
#define OP_PutIntKey          17
#define OP_PutStrKey          18
#define OP_Distinct           19
#define OP_Found              20
#define OP_NotFound           21
#define OP_IsUnique           22
#define OP_NotExists          23
#define OP_Delete             24
#define OP_Column             25
#define OP_KeyAsData          26
#define OP_Recno              27
#define OP_FullKey            28
#define OP_NullRow            29
#define OP_Last               30
#define OP_Rewind             31
#define OP_Next               32

#define OP_Destroy            33
#define OP_Clear              34
#define OP_CreateIndex        35
#define OP_CreateTable        36
#define OP_IntegrityCk        37

#define OP_IdxPut             38
#define OP_IdxDelete          39
#define OP_IdxRecno           40
#define OP_IdxGT              41
#define OP_IdxGE              42

#define OP_MemLoad            43
#define OP_MemStore           44
#define OP_MemIncr            45

#define OP_ListWrite          46
#define OP_ListRewind         47
#define OP_ListRead           48
#define OP_ListReset          49
#define OP_ListPush           50
#define OP_ListPop            51

#define OP_SortPut            52
#define OP_SortMakeRec        53
#define OP_SortMakeKey        54
#define OP_Sort               55
#define OP_SortNext           56
#define OP_SortCallback       57
#define OP_SortReset          58

#define OP_FileOpen           59
#define OP_FileRead           60
#define OP_FileColumn         61

#define OP_AggReset           62
#define OP_AggFocus           63
#define OP_AggNext            64
#define OP_AggSet             65
#define OP_AggGet             66
#define OP_AggFunc            67
#define OP_AggInit            68
#define OP_AggPush            69
#define OP_AggPop             70

#define OP_SetInsert          71
#define OP_SetFound           72
#define OP_SetNotFound        73
#define OP_SetFirst           74
#define OP_SetNext            75

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

#define OP_Goto               80
#define OP_If                 81
#define OP_IfNot              82
#define OP_Halt               83
#define OP_Gosub              84
#define OP_Return             85

#define OP_ColumnCount        86
#define OP_ColumnName         87
#define OP_Callback           88
#define OP_NullCallback       89

#define OP_Integer            90
#define OP_String             91
#define OP_Pop                92
#define OP_Dup                93
#define OP_Pull               94
#define OP_Push               95
#define OP_MustBeInt          96

#define OP_Add                97
#define OP_AddImm             98
#define OP_Subtract           99
#define OP_Multiply          100
#define OP_Divide            101
#define OP_Remainder         102
#define OP_BitAnd            103
#define OP_BitOr             104
#define OP_BitNot            105
#define OP_ShiftLeft         106
#define OP_ShiftRight        107
#define OP_AbsValue          108

/***** IMPORTANT NOTE: The code generator assumes that OP_XX+6==OP_StrXX *****/
#define OP_Eq                109
#define OP_Ne                110
#define OP_Lt                111
#define OP_Le                112
#define OP_Gt                113
#define OP_Ge                114
#define OP_StrEq             115
#define OP_StrNe             116
#define OP_StrLt             117
#define OP_StrLe             118
#define OP_StrGt             119
#define OP_StrGe             120
/***** IMPORTANT NOTE: the code generator assumes that OP_XX+6==OP_StrXX *****/

#define OP_IsNull            121
#define OP_NotNull           122
#define OP_Negative          123
#define OP_And               124
#define OP_Or                125
#define OP_Not               126
#define OP_Concat            127
#define OP_Noop              128
#define OP_Function          129

#define OP_MAX               129

/*
** 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/view.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2002 February 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing VIEW statements.
#
# $Id: view.test,v 1.10 2002/08/25 18:29:16 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test view-1.0 {
  execsql {
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(1,2,3);













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2002 February 26
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing VIEW statements.
#
# $Id: view.test,v 1.11 2002/08/25 19:20:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test view-1.0 {
  execsql {
    CREATE TABLE t1(a,b,c);
    INSERT INTO t1 VALUES(1,2,3);
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294



295

296
297
} {7 2 13 5 19 8 27 12}
do_test view-8.3 {
  execsql {
    CREATE VIEW v7 AS SELECT pqr+xyz AS a FROM v6;
    SELECT * FROM v7 ORDER BY a;
  }
} {9 18 27 39}
if 0 {
do_test view-8.4 {
  execsql { PRAGMA vdbe_trace=on;
    CREATE VIEW v8 AS SELECT max(cnt) FROM
      (SELECT a%2 AS eo, count(*) AS cnt FROM t1 GROUP BY eo);
    SELECT * FROM v8;
  }
} 3



}


finish_test







<

|
|




>
>
>
|
>


280
281
282
283
284
285
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
} {7 2 13 5 19 8 27 12}
do_test view-8.3 {
  execsql {
    CREATE VIEW v7 AS SELECT pqr+xyz AS a FROM v6;
    SELECT * FROM v7 ORDER BY a;
  }
} {9 18 27 39}

do_test view-8.4 {
  execsql {
    CREATE VIEW v8 AS SELECT max(cnt) AS mx FROM
      (SELECT a%2 AS eo, count(*) AS cnt FROM t1 GROUP BY eo);
    SELECT * FROM v8;
  }
} 3
do_test view-8.5 {
  execsql {
    SELECT mx+10, mx*2 FROM v8;
  }
} {13 6}

finish_test