aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2002-08-25 19:20:40 +0000
committerdrh <drh@noemail.net>2002-08-25 19:20:40 +0000
commit8c74a8ca5b056f61879f0e44c0d96551fc99706d (patch)
tree9985f1910dee55acea874e07664133c9a4d75f60 /src
parentd94a66989474da2fb8c3d848b68a941d0876f9ff (diff)
downloadsqlite-8c74a8ca5b056f61879f0e44c0d96551fc99706d.tar.gz
sqlite-8c74a8ca5b056f61879f0e44c0d96551fc99706d.zip
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) FossilOrigin-Name: c602603e7cd8dc5c8bb9db2748eacab650de5bf0
Diffstat (limited to 'src')
-rw-r--r--src/select.c27
-rw-r--r--src/trigger.c4
-rw-r--r--src/vdbe.c163
-rw-r--r--src/vdbe.h271
4 files changed, 275 insertions, 190 deletions
diff --git a/src/select.c b/src/select.c
index 73d766227..cc9a7b554 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.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"
@@ -1403,7 +1403,13 @@ substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){
** 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 */
@@ -1486,6 +1492,7 @@ int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){
}
}
p->isDistinct = p->isDistinct || pSub->isDistinct;
+
if( pSub->nLimit>=0 ){
if( p->nLimit<0 ){
p->nLimit = pSub->nLimit;
@@ -1494,6 +1501,20 @@ int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){
}
}
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);
}
@@ -1883,7 +1904,7 @@ int sqliteSelect(
** 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;
}
diff --git a/src/trigger.c b/src/trigger.c
index 24bd74888..8cbf1fbf6 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -20,7 +20,7 @@ static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext;
- if( pTmp->target.dyn ) sqliteFree(pTmp->target.z);
+ if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
sqliteExprDelete(pTmp->pWhere);
sqliteExprListDelete(pTmp->pExprList);
sqliteSelectDelete(pTmp->pSelect);
@@ -312,8 +312,6 @@ TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
** Recursively delete a Trigger structure
*/
void sqliteDeleteTrigger(Trigger *pTrigger){
- TriggerStep *pTriggerStep;
-
sqliteDeleteTriggerStep(pTrigger->step_list);
sqliteFree(pTrigger->name);
sqliteFree(pTrigger->table);
diff --git a/src/vdbe.c b/src/vdbe.c
index 4a7e2de91..cfd0810bb 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.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>
@@ -1067,35 +1067,36 @@ 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",
+ "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",
};
/*
@@ -1303,6 +1304,25 @@ static void vdbePrintOp(FILE *pOut, int pc, Op *pOp){
#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
@@ -1347,6 +1367,8 @@ int sqliteVdbeExec(
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
@@ -1422,6 +1444,44 @@ case OP_Goto: {
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
@@ -3105,16 +3165,7 @@ case OP_Open: {
}
}
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;
@@ -3163,16 +3214,7 @@ 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;
- }
+ if( expandCursorArraySize(p, i) ) goto no_mem;
pCx = &p->aCsr[i];
cleanupCursor(pCx);
memset(pCx, 0, sizeof(*pCx));
@@ -3195,6 +3237,27 @@ case OP_OpenTemp: {
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
diff --git a/src/vdbe.h b/src/vdbe.h
index 833f71dd1..e35bf2c4c 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.57 2002/06/21 23:01:50 drh Exp $
+** $Id: vdbe.h,v 1.58 2002/08/25 19:20:42 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -82,139 +82,142 @@ typedef struct VdbeOp VdbeOp;
#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
+#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