-C Fix\sthe\smemory\sleak\sintroduced\sby\scheck-in\s(725).\s(CVS\s726)
-D 2002-08-25T18:29:12
+C Fix\sfor\sticket\s#136:\s\sAdded\sthe\sOP_RenameCursor\sVDBE\sinstruction\sand\sused\sit\nto\smake\scursor\snumbers\sright\son\snested\ssubqueries.\s\sAlso\sadded\sOP_Gosub\sand\nOP_Return\sbut\shave\snot\sactually\sused\sthem\sfor\sanything\syet.\s(CVS\s727)
+D 2002-08-25T19:20:40
F Makefile.in bcb81f40d9a17bd94f59e67157b1e1c54c046c2b
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/parse.y 1b180e14b6346e323bd4279469748716f412cc1c
F src/printf.c 5c50fc1da75c8f5bf432b1ad17d91d6653acd167
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c bef25919ad813685d60d03a393728bf5766ec0cb
+F src/select.c e79db94a78368e981af31be4f186bb78ca4081ce
F src/shell.c 9e9a6eb6bca07f01e6472a603f908a0127ea50ff
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in d3999a9c6374675779058d6cfe5431131618e92b
F src/test3.c b99d5ab68ee672f1fbb00520723b5c21bac35822
F src/threadtest.c 72bce0a284647314847bbea44616ceb056bfb77f
F src/tokenize.c 8bd6251e5237c9a16d0bbfb9894925eb129985fa
-F src/trigger.c cc8c6769c2ca37166490ed2b305986268faa3bf8
+F src/trigger.c c90a292a4bef25e478fd5deda6d300319be6a023
F src/update.c f07e6ed2c517c92871e54d3f5886d1cf56121b11
F src/util.c 60bc91db77cf488618ec4720cb06eedb7f959268
-F src/vdbe.c 92bcd4661641fba76680c762971bdca7995594d6
-F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2
+F src/vdbe.c 99b5714751b541a1c64c2c4dede83a474ca6b7e2
+F src/vdbe.h 52ec880c63c6ca74bb6377432149260b1b237873
F src/where.c ce42cce65d7bf42341627f3fb0a17f69fea6a4f4
F test/all.test efd958d048c70a3247997c482f0b33561f7759f0
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/update.test 7ffb062d580a972e7870d0f51d5af3ab9bfeae08
F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
F test/version.test c7057526e14c7e3da5718b88e7f566f4182fd5c5
-F test/view.test ed18cebaa19fa949cad4bc7e7f2d8d71001153cf
+F test/view.test 76d3fe155f1215f9dde1ccad1d1bce5c803132d0
F test/where.test c7aba40ad9178acf9c898e53aac9e447e2d2f2f7
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/lemon.c 022adc2830c2705828f744d2c59798bd462eb465
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 22d8726e61eec0e53893f492cb2163824b87a23e
-R 4234452349011dbb44aad5f2e4ed57e1
+P b957dafc26383af514795df18bc7b8f367c9bd21
+R 1508fec7d872ab78a02b8e4a6441e47b
U drh
-Z 4b5d6fc436ecc6188dd50e32ce24f78e
+Z b7a5fabc6af8b4c88e87d19c813a614d
** 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 $
+** $Id: select.c,v 1.110 2002/08/25 19:20:40 drh Exp $
*/
#include "sqliteInt.h"
** 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){
+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 */
}
}
p->isDistinct = p->isDistinct || pSub->isDistinct;
+
if( pSub->nLimit>=0 ){
if( p->nLimit<0 ){
p->nLimit = pSub->nLimit;
}
}
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);
}
** If flattening is a possiblity, do so and return immediately.
*/
if( pParent && pParentAgg &&
- flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){
+ flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
if( isAgg ) *pParentAgg = 1;
return rc;
}
** 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 $
+** $Id: vdbe.c,v 1.171 2002/08/25 19:20:40 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
"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",
+ "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",
};
/*
}
#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.
**
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
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
}
}
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;
- }
+ if( expandCursorArraySize(p, i) ) goto no_mem;
cleanupCursor(&p->aCsr[i]);
memset(&p->aCsr[i], 0, sizeof(Cursor));
p->aCsr[i].nullRow = 1;
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;
- }
+ if( expandCursorArraySize(p, i) ) goto no_mem;
pCx = &p->aCsr[i];
cleanupCursor(pCx);
memset(pCx, 0, sizeof(*pCx));
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