Fix many problems with manifest types and column affinity. Most things are
working now. (CVS 1392) FossilOrigin-Name: a62872aacd544a1465b06e007153168663f3c83a
This commit is contained in:
parent
eb015e03e1
commit
84ac9d02dd
26
manifest
26
manifest
@ -1,5 +1,5 @@
|
||||
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
|
||||
@ -26,16 +26,16 @@ F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
|
||||
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
|
||||
@ -43,10 +43,10 @@ F src/os.h fbb2f6595fc34fa351830d88fe1c6b85118f0383
|
||||
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
|
||||
@ -59,14 +59,14 @@ F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296
|
||||
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
|
||||
@ -192,7 +192,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
||||
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
|
||||
|
@ -1 +1 @@
|
||||
c1745f47ae6597953426c852559c3ba559b5ecd4
|
||||
a62872aacd544a1465b06e007153168663f3c83a
|
10
src/build.c
10
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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
12
src/pragma.c
12
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.
|
||||
*/
|
||||
|
174
src/select.c
174
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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
243
src/vdbe.c
243
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++;
|
||||
|
||||
/* 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 ){
|
||||
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;
|
||||
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( i<0 ){
|
||||
assert( &pTos[i]>=p->aStack );
|
||||
assert( pTos[i].flags & MEM_Str );
|
||||
zRec = pTos[i].z;
|
||||
payloadSize = pTos[i].n;
|
||||
pC->cacheValid = 0;
|
||||
assert(!"broken for now");
|
||||
}else if( (pC = p->apCsr[i])->pCursor!=0 ){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user