aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2004-05-18 09:58:06 +0000
committerdanielk1977 <danielk1977@noemail.net>2004-05-18 09:58:06 +0000
commit84ac9d02dd8ff5d03ce8bc5e91a68c0989633eef (patch)
treee318aef61a7685902c7a485e0fa5c91b12be84e0 /src
parenteb015e03e1c1e436bf17d457d8f98cc26e97aa41 (diff)
downloadsqlite-84ac9d02dd8ff5d03ce8bc5e91a68c0989633eef.tar.gz
sqlite-84ac9d02dd8ff5d03ce8bc5e91a68c0989633eef.zip
Fix many problems with manifest types and column affinity. Most things are
working now. (CVS 1392) FossilOrigin-Name: a62872aacd544a1465b06e007153168663f3c83a
Diffstat (limited to 'src')
-rw-r--r--src/build.c10
-rw-r--r--src/delete.c5
-rw-r--r--src/insert.c7
-rw-r--r--src/pragma.c12
-rw-r--r--src/select.c174
-rw-r--r--src/update.c6
-rw-r--r--src/vdbe.c243
-rw-r--r--src/vdbeaux.c59
8 files changed, 340 insertions, 176 deletions
diff --git a/src/build.c b/src/build.c
index d26ad6a55..a1cd608b5 100644
--- a/src/build.c
+++ b/src/build.c
@@ -23,7 +23,7 @@
** ROLLBACK
** PRAGMA
**
-** $Id: build.c,v 1.186 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: build.c,v 1.187 2004/05/18 09:58:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -790,7 +790,7 @@ char sqlite3AffinityType(const char *zType, int nType){
for(n=0; n<(nType-2); n++){
for(i=0; i<sizeof(substrings)/sizeof(substrings[0]); i++){
- if( 0==sqlite3StrNICmp(zType, substrings[i].zSub, substrings[i].nSub) ){
+ if( 0==sqlite3StrNICmp(&zType[n], substrings[i].zSub, substrings[i].nSub) ){
return substrings[i].affinity;
}
}
@@ -992,7 +992,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
sqlite3VdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
}
- sqlite3VdbeAddOp(v, OP_MakeRecord, 5, 0);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
if( !p->iDb ){
sqlite3ChangeCookie(db, v);
@@ -1002,7 +1002,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
pParse->nTab = 2;
- sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
+ sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
}
sqlite3EndWriteOperation(pParse);
}
@@ -1720,7 +1720,7 @@ void sqlite3CreateIndex(
n = Addr(pEnd->z) - Addr(pStart->z) + 1;
sqlite3VdbeChangeP3(v, addr, pStart->z, n);
}
- sqlite3VdbeAddOp(v, OP_MakeRecord, 5, 0);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
if( pTable ){
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
diff --git a/src/delete.c b/src/delete.c
index 66497002f..df1a0485d 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
-** $Id: delete.c,v 1.66 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: delete.c,v 1.67 2004/05/18 09:58:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -149,7 +149,7 @@ void sqlite3DeleteFrom(
*/
if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
@@ -213,6 +213,7 @@ void sqlite3DeleteFrom(
*/
if( row_triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
diff --git a/src/insert.c b/src/insert.c
index f572bb893..12ed4a4d5 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.101 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: insert.c,v 1.102 2004/05/18 09:58:07 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -260,7 +260,7 @@ void sqlite3Insert(
iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
iSelectLoop = sqlite3VdbeCurrentAddr(v);
iInsertBlock = sqlite3VdbeMakeLabel(v);
- rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0);
+ rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0,0);
if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
iCleanup = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
@@ -278,7 +278,7 @@ void sqlite3Insert(
if( row_triggers_exist ){
useTempTable = 1;
}else{
- int addr = sqlite3VdbeFindOp(v, OP_OpenRead, pTab->tnum);
+ int addr = sqlite3VdbeFindOp(v, 0, OP_OpenRead, pTab->tnum);
useTempTable = 0;
if( addr>0 ){
VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-2);
@@ -398,6 +398,7 @@ void sqlite3Insert(
*/
if( row_triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
}
/* Initialize the count of rows to be inserted
diff --git a/src/pragma.c b/src/pragma.c
index b0be50a25..aafa1451d 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.24 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: pragma.c,v 1.25 2004/05/18 09:58:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -622,11 +622,11 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
*/
addr = sqlite3VdbeAddOpList(v, ArraySize(checkDb), checkDb);
sqlite3VdbeChangeP1(v, addr+1, i);
- sqlite3VdbeChangeP2(v, addr+3, addr+7);
- sqlite3VdbeChangeP2(v, addr+6, addr+4);
- sqlite3VdbeChangeP2(v, addr+7, i);
- sqlite3VdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
- sqlite3VdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);
+ sqlite3VdbeChangeP2(v, addr+4, addr+8);
+ sqlite3VdbeChangeP2(v, addr+7, addr+5);
+ sqlite3VdbeChangeP2(v, addr+8, i);
+ sqlite3VdbeChangeP2(v, addr+11, addr+ArraySize(checkDb));
+ sqlite3VdbeChangeP3(v, addr+14, db->aDb[i].zName, P3_STATIC);
/* Make sure all the indices are constructed correctly.
*/
diff --git a/src/select.c b/src/select.c
index ac715fa0b..a27e7aa24 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.166 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: select.c,v 1.167 2004/05/18 09:58:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -382,7 +382,8 @@ static int selectInnerLoop(
int eDest, /* How to dispose of the results */
int iParm, /* An argument to the disposal method */
int iContinue, /* Jump here to continue with next row */
- int iBreak /* Jump here to break out of the inner loop */
+ int iBreak, /* Jump here to break out of the inner loop */
+ char *aff /* affinity string if eDest is SRT_Union */
){
Vdbe *v = pParse->pVdbe;
int i;
@@ -440,6 +441,7 @@ static int selectInnerLoop(
*/
case SRT_Union: {
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
+ sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
sqlite3VdbeAddOp(v, OP_String, 0, 0);
sqlite3VdbeAddOp(v, OP_PutStrKey, iParm, 0);
break;
@@ -467,6 +469,7 @@ static int selectInnerLoop(
case SRT_Except: {
int addr;
addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
+ sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3);
sqlite3VdbeAddOp(v, OP_Delete, iParm, 0);
break;
@@ -491,7 +494,7 @@ static int selectInnerLoop(
char aff = (iParm>>16)&0xFF;
aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
affStr = sqlite3AffinityString(aff);
- sqlite3VdbeOp3(v, OP_MakeKey, 1, 1, affStr, P3_STATIC);
+ sqlite3VdbeOp3(v, OP_MakeKey, 1, 0, affStr, P3_STATIC);
sqlite3VdbeAddOp(v, OP_String, 0, 0);
sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0);
}
@@ -612,11 +615,13 @@ static void generateSortTail(
}
case SRT_Subroutine: {
int i;
+ sqlite3VdbeAddOp(v, OP_Integer, p->pEList->nExpr, 0);
+ sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
for(i=0; i<nColumn; i++){
sqlite3VdbeAddOp(v, OP_Column, -1-i, i);
}
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
break;
}
default: {
@@ -1208,6 +1213,19 @@ static void multiSelectSortOrder(Select *p, ExprList *pOrderBy){
}
}
+static void multiSelectAffinity(Select *p, char *zAff){
+ int i;
+
+ if( !p ) return;
+ multiSelectAffinity(p->pPrior, zAff);
+
+ for(i=0; i<p->pEList->nExpr; i++){
+ if( zAff[i]=='\0' ){
+ zAff[i] = sqlite3ExprAffinity(p->pEList->a[i].pExpr);
+ }
+ }
+}
+
/*
** Compute the iLimit and iOffset fields of the SELECT based on the
** nLimit and nOffset fields. nLimit and nOffset hold the integers
@@ -1284,31 +1302,62 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
** Notice that because of the way SQLite parses compound SELECTs, the
** individual selects always group from left to right.
*/
-static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
- int rc; /* Success code from a subroutine */
+static int multiSelect(
+ Parse *pParse,
+ Select *p,
+ int eDest,
+ int iParm,
+ char *aff /* If eDest is SRT_Union, the affinity string */
+){
+ int rc = SQLITE_OK; /* Success code from a subroutine */
Select *pPrior; /* Another SELECT immediately to our left */
Vdbe *v; /* Generate code to this VDBE */
+ char *affStr = 0;
+
+ if( !aff ){
+ int len;
+ rc = fillInColumnList(pParse, p);
+ if( rc!=SQLITE_OK ){
+ goto multi_select_end;
+ }
+ len = p->pEList->nExpr+1;
+ affStr = (char *)sqliteMalloc(p->pEList->nExpr+1);
+ if( !affStr ){
+ rc = SQLITE_NOMEM;
+ goto multi_select_end;
+ }
+ memset(affStr, (int)SQLITE_AFF_NUMERIC, len-1);
+ aff = affStr;
+ }
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
** the last SELECT in the series may have an ORDER BY or LIMIT.
*/
- if( p==0 || p->pPrior==0 ) return 1;
+ if( p==0 || p->pPrior==0 ){
+ rc = 1;
+ goto multi_select_end;
+ }
pPrior = p->pPrior;
if( pPrior->pOrderBy ){
sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
selectOpName(p->op));
- return 1;
+ rc = 1;
+ goto multi_select_end;
}
if( pPrior->nLimit>=0 || pPrior->nOffset>0 ){
sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
selectOpName(p->op));
- return 1;
+ rc = 1;
+ goto multi_select_end;
}
/* Make sure we have a valid query engine. If not, create a new one.
*/
v = sqlite3GetVdbe(pParse);
- if( v==0 ) return 1;
+ if( v==0 ){
+ rc = 1;
+ goto multi_select_end;
+ }
/* Create the destination temporary table if necessary
*/
@@ -1326,16 +1375,20 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
if( p->pOrderBy==0 ){
pPrior->nLimit = p->nLimit;
pPrior->nOffset = p->nOffset;
- rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0);
- if( rc ) return rc;
+ rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
+ if( rc ){
+ goto multi_select_end;
+ }
p->pPrior = 0;
p->iLimit = pPrior->iLimit;
p->iOffset = pPrior->iOffset;
p->nLimit = -1;
p->nOffset = 0;
- rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0);
+ rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
p->pPrior = pPrior;
- if( rc ) return rc;
+ if( rc ){
+ goto multi_select_end;
+ }
break;
}
/* For UNION ALL ... ORDER BY fall through to the next case */
@@ -1361,7 +1414,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
unionTab = pParse->nTab++;
if( p->pOrderBy
&& matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
- return 1;
+ rc = 1;
+ goto multi_select_end;
}
if( p->op!=TK_ALL ){
sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 1);
@@ -1369,12 +1423,18 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
}else{
sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0);
}
+ assert( p->pEList );
}
/* Code the SELECT statements to our left
*/
- rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0);
- if( rc ) return rc;
+ rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
+ if( rc ){
+ goto multi_select_end;
+ }
+ if( p->op==TK_ALL ){
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, unionTab, pPrior->pEList->nExpr);
+ }
/* Code the current SELECT statement
*/
@@ -1390,12 +1450,15 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
p->nLimit = -1;
nOffset = p->nOffset;
p->nOffset = 0;
- rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0);
+ rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
p->pPrior = pPrior;
p->pOrderBy = pOrderBy;
p->nLimit = nLimit;
p->nOffset = nOffset;
- if( rc ) return rc;
+ if( rc ){
+ goto multi_select_end;
+ }
+
/* Convert the data in the temporary table into whatever form
** it is that we currently need.
@@ -1415,8 +1478,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
multiSelectSortOrder(p, p->pOrderBy);
rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
p->pOrderBy, -1, eDest, iParm,
- iCont, iBreak);
- if( rc ) return 1;
+ iCont, iBreak, 0);
+ if( rc ){
+ rc = 1;
+ goto multi_select_end;
+ }
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
@@ -1439,15 +1505,19 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
tab1 = pParse->nTab++;
tab2 = pParse->nTab++;
if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
- return 1;
+ rc = 1;
+ goto multi_select_end;
}
sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 1);
sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1);
+ assert( p->pEList );
/* Code the SELECTs to our left into temporary table "tab1".
*/
- rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0);
- if( rc ) return rc;
+ rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
+ if( rc ){
+ goto multi_select_end;
+ }
/* Code the current SELECT into temporary table "tab2"
*/
@@ -1458,11 +1528,13 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
p->nLimit = -1;
nOffset = p->nOffset;
p->nOffset = 0;
- rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0);
+ rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
p->pPrior = pPrior;
p->nLimit = nLimit;
p->nOffset = nOffset;
- if( rc ) return rc;
+ if( rc ){
+ goto multi_select_end;
+ }
/* Generate code to take the intersection of the two temporary
** tables.
@@ -1481,8 +1553,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
multiSelectSortOrder(p, p->pOrderBy);
rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
p->pOrderBy, -1, eDest, iParm,
- iCont, iBreak);
- if( rc ) return 1;
+ iCont, iBreak, 0);
+ if( rc ){
+ rc = 1;
+ goto multi_select_end;
+ }
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp(v, OP_Next, tab1, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
@@ -1498,9 +1573,20 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
" do not have the same number of result columns", selectOpName(p->op));
- return 1;
+ rc = 1;
+ goto multi_select_end;
}
- return 0;
+
+multi_select_end:
+ if( affStr ){
+ if( rc!=SQLITE_OK ){
+ sqliteFree(affStr);
+ }else{
+ multiSelectAffinity(p, affStr);
+ sqlite3VdbeOp3(v, OP_Noop, 0, 0, affStr, P3_DYNAMIC);
+ }
+ }
+ return rc;
}
/*
@@ -1937,7 +2023,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
memset(&eListItem, 0, sizeof(eListItem));
eList.a = &eListItem;
eList.a[0].pExpr = pExpr;
- selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont);
+ selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0);
sqlite3VdbeResolveLabel(v, cont);
sqlite3VdbeAddOp(v, OP_Close, base, 0);
@@ -2003,7 +2089,8 @@ int sqlite3Select(
int iParm, /* A parameter used by the eDest disposal method */
Select *pParent, /* Another SELECT for which this is a sub-query */
int parentTab, /* Index in pParent->pSrc of this query */
- int *pParentAgg /* True if pParent uses aggregate functions */
+ int *pParentAgg, /* True if pParent uses aggregate functions */
+ char *aff /* If eDest is SRT_Union, the affinity string */
){
int i;
WhereInfo *pWInfo;
@@ -2025,7 +2112,7 @@ int sqlite3Select(
/* If there is are a sequence of queries, do the earlier ones first.
*/
if( p->pPrior ){
- return multiSelect(pParse, p, eDest, iParm);
+ return multiSelect(pParse, p, eDest, iParm, aff);
}
/* Make local copies of the parameters for this query.
@@ -2181,6 +2268,21 @@ int sqlite3Select(
generateColumnNames(pParse, pTabList, pEList);
}
+ /* If the destination is SRT_Union, then set the number of columns in
+ ** the records that will be inserted into the temporary table. The caller
+ ** couldn't do this, in case the select statement is of the form
+ ** "SELECT * FROM ....".
+ **
+ ** We need to do this before we start inserting records into the
+ ** temporary table (which has had OP_KeyAsData executed on it), because
+ ** it is required by the key comparison function. So do it now, even
+ ** though this means that OP_SetNumColumns may be executed on the same
+ ** cursor more than once.
+ */
+ if( eDest==SRT_Union ){
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
+ }
+
/* Generate code for all sub-queries in the FROM clause
*/
for(i=0; i<pTabList->nSrc; i++){
@@ -2196,7 +2298,7 @@ int sqlite3Select(
needRestoreContext = 0;
}
sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable,
- pTabList->a[i].iCursor, p, i, &isAgg);
+ pTabList->a[i].iCursor, p, i, &isAgg, 0);
if( needRestoreContext ){
pParse->zAuthContext = zSavedAuthContext;
}
@@ -2324,7 +2426,7 @@ int sqlite3Select(
*/
if( !isAgg ){
if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
- iParm, pWInfo->iContinue, pWInfo->iBreak) ){
+ iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){
goto select_end;
}
}
@@ -2383,7 +2485,7 @@ int sqlite3Select(
sqlite3ExprIfFalse(pParse, pHaving, startagg, 1);
}
if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
- iParm, startagg, endagg) ){
+ iParm, startagg, endagg, aff) ){
goto select_end;
}
sqlite3VdbeAddOp(v, OP_Goto, 0, startagg);
diff --git a/src/update.c b/src/update.c
index d234f5e35..71c6c6f84 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.75 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: update.c,v 1.76 2004/05/18 09:58:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -216,7 +216,7 @@ void sqlite3Update(
if( isView ){
Select *pView;
pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
@@ -243,7 +243,9 @@ void sqlite3Update(
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
/* The top of the update loop for when there are triggers.
*/
diff --git a/src/vdbe.c b/src/vdbe.c
index 52b8c8ac5..f09d3b9b2 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.297 2004/05/18 01:23:38 danielk1977 Exp $
+** $Id: vdbe.c,v 1.298 2004/05/18 09:58:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -485,6 +485,57 @@ static void applyAffinity(Mem *pRec, char affinity){
}
}
+static int getBtreeMem(
+ BtCursor *pCur, /* Cursor pointing at record to retrieve. */
+ int offset, /* Offset from the start of data to return bytes from. */
+ int amt, /* Number of bytes to return. */
+ int key, /* If true, retrieve from the btree key, not data. */
+ Mem *pMem /* OUT: Return data in this Mem structure. */
+){
+ char *zData;
+
+ if( key ){
+ zData = (char *)sqlite3BtreeKeyFetch(pCur, offset+amt);
+ }else{
+ zData = (char *)sqlite3BtreeDataFetch(pCur, offset+amt);
+ }
+
+ if( zData ){
+ pMem->z = &zData[offset];
+ pMem->n = amt;
+ pMem->flags = MEM_Blob|MEM_Ephem;
+ }else{
+ int rc;
+ if( amt>NBFS ){
+ zData = (char *)sqliteMallocRaw(amt);
+ if( !zData ){
+ return SQLITE_NOMEM;
+ }
+ pMem->flags = MEM_Blob|MEM_Dyn;
+ }else{
+ zData = &(pMem->zShort[0]);
+ pMem->flags = MEM_Blob|MEM_Short;
+ }
+ pMem->z = zData;
+
+ if( key ){
+ rc = sqlite3BtreeKey(pCur, offset, amt, zData);
+ }else{
+ rc = sqlite3BtreeData(pCur, offset, amt, zData);
+ }
+
+ if( rc!=SQLITE_OK ){
+ if( amt>NBFS ){
+ sqliteFree(zData);
+ }
+ return rc;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+
#ifdef VDBE_PROFILE
/*
** The following routine only works on pentium-class processors.
@@ -2019,7 +2070,8 @@ case OP_SetNumColumns: {
** a table. For P1==-1, the top of the stack is used. For P1==-2, the
** next on the stack is used. And so forth. The value pushed is always
** just a pointer into the record which is stored further down on the
-** stack. The column value is not copied.
+** stack. The column value is not copied. The number of columns in the
+** record is stored on the stack just above the record itself.
*/
case OP_Column: {
int payloadSize; /* Number of bytes in the record */
@@ -2029,30 +2081,61 @@ case OP_Column: {
char *zRec; /* Pointer to record-data from stack or pseudo-table. */
BtCursor *pCrsr;
- char *zData;
- int freeZdata = 0; /* zData requires sqliteFree() */
-
u64 nField; /* number of fields in the record */
-
int len; /* The length of the serialized data for the column */
int offset = 0;
int nn;
+ char *zData;
+ Mem zMem;
+ zMem.flags = 0;
+
assert( i<p->nCursor );
pTos++;
- /* This block sets the variable payloadSize, and if the data is coming
- ** from the stack or from a pseudo-table zRec. If the data is coming
- ** from a real cursor, then zRec is left as NULL.
+ /* If the record is coming from the stack, not from a cursor, then there
+ ** is nowhere to cache the record header infomation. This simplifies
+ ** things greatly, so deal with this case seperately.
*/
if( i<0 ){
- assert( &pTos[i]>=p->aStack );
+ char *zRec; /* Pointer to record data from the stack. */
+ int off = 0; /* Offset in zRec to start of the columns data. */
+ int off2 = 0; /* Offset in zRec to the next serial type to read */
+ u64 colType; /* The serial type of the value being read. */
+
+ assert( &pTos[i-1]>=p->aStack );
assert( pTos[i].flags & MEM_Str );
+ assert( pTos[i-1].flags & MEM_Int );
+
+ if( pTos[i].n==0 ){
+ pTos->flags = MEM_Null;
+ break;
+ }
+
zRec = pTos[i].z;
- payloadSize = pTos[i].n;
- pC->cacheValid = 0;
- assert(!"broken for now");
- }else if( (pC = p->apCsr[i])->pCursor!=0 ){
+ nField = pTos[i-1].i;
+
+ for( nn=0; nn<nField; nn++ ){
+ u64 v;
+ off2 += sqlite3GetVarint(&zRec[off2], &v);
+ if( nn==p2 ){
+ colType = v;
+ }else if( nn<p2 ){
+ off += sqlite3VdbeSerialTypeLen(v);
+ }
+ }
+ off += off2;
+
+ sqlite3VdbeSerialGet(&zRec[off], colType, pTos);
+ break;
+ }
+
+
+ /* This block sets the variable payloadSize, and if the data is coming
+ ** from the stack or from a pseudo-table zRec. If the data is coming
+ ** from a real cursor, then zRec is left as NULL.
+ */
+ if( (pC = p->apCsr[i])->pCursor!=0 ){
sqlite3VdbeCursorMoveto(pC);
zRec = 0;
pCrsr = pC->pCursor;
@@ -2093,31 +2176,8 @@ case OP_Column: {
/* Read and parse the table header. Store the results of the parse
** into the record header cache fields of the cursor.
*/
- if( !pC->cacheValid ){
+ if( !pC || !pC->cacheValid ){
pC->payloadSize = payloadSize;
-#if 0
- if( zRec ){
- zData = zRec;
- }else{
- /* We can assume that 10 bytes (maximum length of a varint) fits
- ** on the main page in all cases.
- */
- int n = 10;
- if( payloadSize<10 ) n = payloadSize;
- if( pC->keyAsData ){
- zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n);
- }else{
- zData = (char *)sqlite3BtreeDataFetch(pCrsr, n);
- }
- assert( zData );
- }
- {
- u64 x;
- offset = sqlite3GetVarint(zData, &x);
- assert( x==nField );
- }
-#endif
-
if( !pC->aType ){
pC->aType = sqliteMallocRaw( nField*sizeof(pC->aType[0]) );
if( pC->aType==0 ){
@@ -2125,52 +2185,28 @@ case OP_Column: {
}
}
- if( !zRec ){
- /* If the record is stored in a table, see if enough of it is on
- ** the main page to use sqlite3BtreeDataFetch() to get the data
- ** containing the nField serial types (varints). This will almost
- ** always work, but if it doesn't sqliteMalloc() space and use
- ** sqlite3BtreeData().
- **
- ** Estimate the maximum space required by the nField varints by
+ if( zRec ){
+ zData = zRec;
+ }else{
+ /* Estimate the maximum space required by the nField varints by
** assuming the maximum space for each is the length required to store:
**
** (<record length> * 2) + 13
**
** This is the serial-type for a text object as long as the record
- ** itself. In all cases the length required to store this is three
- ** bytes or less.
+ ** itself. In almost all cases the length required to store this is
+ ** three bytes or less.
*/
int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField;
- max_space += offset;
if( max_space>payloadSize ){
max_space = payloadSize;
}
- if( pC->keyAsData ){
- zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space);
- }else{
- zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space);
- }
- if( !zData ){
- /* This code will run very infrequently (e.g. tables with several
- ** hundred columns).
- */
- zData = (char *)sqliteMallocRaw(max_space);
- if( !zData ){
- goto no_mem;
- }
- if( pC->keyAsData ){
- rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData);
- }else{
- rc = sqlite3BtreeData(pCrsr, 0, max_space, zData);
- }
- if( rc!=SQLITE_OK ){
- sqliteFree(zData);
- goto abort_due_to_error;
- }
- freeZdata = 1;
+ rc = getBtreeMem(pCrsr, 0, max_space, pC->keyAsData, &zMem);
+ if( rc!=SQLITE_OK ){
+ goto abort_due_to_error;
}
+ zData = zMem.z;
}
/* Read all the serial types for the record. At the end of this block
@@ -2179,12 +2215,11 @@ case OP_Column: {
for(nn=0; nn<nField; nn++){
offset += sqlite3GetVarint(&zData[offset], &pC->aType[nn]);
}
- if( freeZdata ){
- freeZdata = 0;
- sqliteFree(zData);
- }
pC->nHeader = offset;
pC->cacheValid = 1;
+
+ Release(&zMem);
+ zMem.flags = 0;
}
/* Compute the offset from the beginning of the record to the beginning
@@ -2194,44 +2229,17 @@ case OP_Column: {
for(nn=0; nn<p2; nn++){
offset += sqlite3VdbeSerialTypeLen(pC->aType[nn]);
}
- len = sqlite3VdbeSerialTypeLen(pC->aType[p2]);
- if( !zRec ){
- /* If the record is stored in a table, see if enough of it
- ** is on the main page to read our column using
- ** sqlite3BtreeDataFetch(). If not sqliteMalloc() space and read data
- ** with sqlite3BtreeData().
- */
- if( pC->keyAsData ){
- zData = (char *)sqlite3BtreeKeyFetch(pCrsr, offset+len);
- }else{
- zData = (char *)sqlite3BtreeDataFetch(pCrsr, offset+len);
- }
- if( !zData ){
- zData = (char *)sqliteMallocRaw(len);
- if( !zData ){
- goto no_mem;
- }
- if( pC->keyAsData ){
- rc = sqlite3BtreeKey(pCrsr, offset, len, zData);
- }else{
- rc = sqlite3BtreeData(pCrsr, offset, len, zData);
- }
- if( rc!=SQLITE_OK ){
- sqliteFree( zData );
- goto abort_due_to_error;
- }
- freeZdata = 1;
- offset = 0;
- }
+ if( zRec ){
+ zData = &zRec[offset];
+ }else{
+ len = sqlite3VdbeSerialTypeLen(pC->aType[p2]);
+ getBtreeMem(pCrsr, offset, len, pC->keyAsData, &zMem);
+ zData = zMem.z;
}
+ sqlite3VdbeSerialGet(zData, pC->aType[p2], pTos);
- /* Deserialize the value directly into the top of the stack */
- sqlite3VdbeSerialGet(&zData[offset], pC->aType[p2], pTos);
-
- if( freeZdata ){
- sqliteFree(zData);
- }
+ Release(&zMem);
break;
}
@@ -2293,7 +2301,6 @@ case OP_MakeRecord: {
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
- // nBytes = sqlite3VarintLen(nField);
for(pRec=pData0; pRec<=pTos; pRec++){
u64 serial_type;
if( zAffinity ){
@@ -2317,7 +2324,6 @@ case OP_MakeRecord: {
/* Write the record */
zCsr = zNewRecord;
- // zCsr += sqlite3PutVarint(zCsr, nField); /* number of fields */
for(pRec=pData0; pRec<=pTos; pRec++){
u64 serial_type = sqlite3VdbeSerialType(pRec);
zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */
@@ -2348,9 +2354,9 @@ case OP_MakeRecord: {
/* Opcode: MakeKey P1 P2 P3
**
** Convert the top P1 entries of the stack into a single entry suitable
-** for use as the key in an index. If P2 is not zero, then the original
-** entries are popped off the stack. If P2 is zero, the original entries
-** remain on the stack.
+** for use as the key in an index. If P2 is zero, then the original
+** entries are popped off the stack. If P2 is not zero, the original
+** entries remain on the stack.
**
** P3 is interpreted in the same way as for MakeIdxKey.
*/
@@ -3449,11 +3455,16 @@ case OP_SetCounts: {
** off (if P2==0). In key-as-data mode, the OP_Column opcode pulls
** data off of the key rather than the data. This is used for
** processing compound selects.
+**
+** This opcode also instructs the cursor that the keys used will be
+** serialized in the record format usually used for table data, not
+** the usual index key format.
*/
case OP_KeyAsData: {
int i = pOp->p1;
assert( i>=0 && i<p->nCursor );
p->apCsr[i]->keyAsData = pOp->p2;
+ sqlite3BtreeSetCompare(p->apCsr[i]->pCursor, sqlite3VdbeRowCompare, p->apCsr[i]);
break;
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 4814647fb..c5a464b2b 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -366,13 +366,14 @@ void sqlite3VdbeCompressSpace(Vdbe *p, int addr){
}
/*
-** Search for the current program for the given opcode and P2
-** value. Return the address plus 1 if found and 0 if not found.
+** Search the current program starting at instruction addr for the given
+** opcode and P2 value. Return the address plus 1 if found and 0 if not
+** found.
*/
-int sqlite3VdbeFindOp(Vdbe *p, int op, int p2){
+int sqlite3VdbeFindOp(Vdbe *p, int addr, int op, int p2){
int i;
assert( p->magic==VDBE_MAGIC_INIT );
- for(i=0; i<p->nOp; i++){
+ for(i=addr; i<p->nOp; i++){
if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
}
return 0;
@@ -1478,7 +1479,7 @@ int sqlite3VdbeKeyCompare(
** or positive integer if {nKey1, pKey1} is less than, equal to or
** greater than {nKey2, pKey2}.
**
-** This function is pretty inefficient and will probably be replace
+** This function is pretty inefficient and will probably be replaced
** by something else in the near future. It is currently required
** by compound SELECT operators.
*/
@@ -1487,12 +1488,58 @@ int sqlite3VdbeRowCompare(
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
){
+ Cursor *pC = (Cursor *)userData;
int offset1 = 0;
int offset2 = 0;
+ int toffset1 = 0;
+ int toffset2 = 0;
+ int i;
const unsigned char *aKey1 = (const unsigned char *)pKey1;
const unsigned char *aKey2 = (const unsigned char *)pKey2;
- assert( userData==0 );
+ assert( pC );
+ assert( pC->nField>0 );
+
+ for( i=0; i<pC->nField; i++ ){
+ u64 dummy;
+ offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy);
+ offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy);
+ }
+
+ for( i=0; i<pC->nField; i++ ){
+ Mem mem1;
+ Mem mem2;
+ u64 serial_type1;
+ u64 serial_type2;
+ int rc;
+
+ /* Read the serial types for the next element in each key. */
+ toffset1 += sqlite3GetVarint(&aKey1[toffset1], &serial_type1);
+ toffset2 += sqlite3GetVarint(&aKey2[toffset2], &serial_type2);
+
+ assert( serial_type1 && serial_type2 );
+
+ /* Assert that there is enough space left in each key for the blob of
+ ** data to go with the serial type just read. This assert may fail if
+ ** the file is corrupted. Then read the value from each key into mem1
+ ** and mem2 respectively.
+ */
+ offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1);
+ offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2);
+
+ rc = sqlite3MemCompare(&mem1, &mem2);
+ if( mem1.flags&MEM_Dyn ){
+ sqliteFree(mem1.z);
+ }
+ if( mem2.flags&MEM_Dyn ){
+ sqliteFree(mem2.z);
+ }
+ if( rc!=0 ){
+ return rc;
+ }
+ }
+
+ return 0;
}