-C Bugfix\sfor\srow\sformat.\s(CVS\s1391)
-D 2004-05-18T01:31:14
+C Fix\smany\sproblems\swith\smanifest\stypes\sand\scolumn\saffinity.\sMost\sthings\sare\nworking\snow.\s(CVS\s1392)
+D 2004-05-18T09:58:07
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/btree.c bf8d9592b66fb9ba89a5be13fd99a7d8b8a67d7f
F src/btree.h 6f51ad0ffebfba71295fcacdbe86007512200050
F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
-F src/build.c ddb0384afd2c82599b7d2bdefc4878850854931c
+F src/build.c 84a9b37700a18db370b9dbb77f1636df5cdf0290
F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
-F src/delete.c 8cb317fbba81b428301bccf04be1bea22203508b
+F src/delete.c a069dcc2ec0cc3487c8ababebc59a429b4556144
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
F src/expr.c d39afb30c76c2f67fb5ffdfe530ed709c5009786
F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 72d9dd0b2543420a905ada68f098bc6754b8a1ea
+F src/insert.c 60cc57b8468749d7e023798b9d7f91eeb4cd279a
F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5
F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253
F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
-F src/pragma.c 2c65f46a520cd3bab49623d68bec0a5afaae5b52
+F src/pragma.c fcbd8bc7f2cc1429758a042920e13c8738a6050c
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 62431fb1a1021301e35f12f64c325d5f20371393
+F src/select.c f376f3beade0e1e4808b3a393c13f5b30baecf74
F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
F src/sqliteInt.h ac5fe07df6cf0a4c935e5a88bc14bc620e4f1591
F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847
F src/trigger.c 8df308e09113410bb895e88a2db65b55490268db
-F src/update.c d14a0b0f3b35ea2469dda375e59a1064f02c7c0e
+F src/update.c 0cc7291dd0e0f82cf93085e49c973e8ef9e51fd5
F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf
F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
-F src/vdbe.c 8a6b971c130227fc90a6e899afe218277aa29fdd
+F src/vdbe.c 5cc6e41f2c9f24bbbf591ca538c097c0f7b41a3d
F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
F src/vdbeInt.h 311c2a046ea419781d0ef331198b7b0a65eebc92
-F src/vdbeaux.c 618861394df84d475e574e22b95e6ed1c9453b1d
+F src/vdbeaux.c 760105ceedb7bcfcd3f4dbba7a5500321612669b
F src/where.c 5f480219a943b0fed1f6922d2fdbfba8616a9148
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P 202a470f2c1804a96e69f16709d1a92e405971f0
-R ffc409e8b16e570dc32c405b3b469d03
+P c1745f47ae6597953426c852559c3ba559b5ecd4
+R 02c7a45ac0cf509a83f0308e5e2e8fde
U danielk1977
-Z 5eff88f75ed7e1dd3ba47379b0123d5b
+Z 6d5d78b2c759d8987f601a926f92d5bb
-c1745f47ae6597953426c852559c3ba559b5ecd4
\ No newline at end of file
+a62872aacd544a1465b06e007153168663f3c83a
\ No newline at end of file
** 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>
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;
}
}
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);
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);
}
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);
** 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"
*/
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);
}
*/
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
** 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"
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);
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);
*/
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
*************************************************************************
** 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>
*/
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.
*/
** 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"
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;
*/
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;
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;
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);
}
}
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: {
}
}
+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
** 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
*/
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 */
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);
}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
*/
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.
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);
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"
*/
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.
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);
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;
}
/*
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);
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;
/* 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.
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++){
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;
}
*/
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;
}
}
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);
** 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"
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);
}
/* 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.
*/
** 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"
}
}
+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.
** 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 */
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;
/* 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 ){
}
}
- 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
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
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;
}
/* 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 ){
/* 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 */
/* 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.
*/
** 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;
}
}
/*
-** 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;
** 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.
*/
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;
}