diff --git a/manifest b/manifest index b470d8842a..35ceb50b40 100644 --- a/manifest +++ b/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 diff --git a/manifest.uuid b/manifest.uuid index 02e88e32a7..fcc0512093 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1745f47ae6597953426c852559c3ba559b5ecd4 \ No newline at end of file +a62872aacd544a1465b06e007153168663f3c83a \ No newline at end of file diff --git a/src/build.c b/src/build.c index d26ad6a55d..a1cd608b5c 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 @@ -790,7 +790,7 @@ char sqlite3AffinityType(const char *zType, int nType){ for(n=0; n<(nType-2); n++){ for(i=0; iz) - 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 66497002f1..df1a0485d5 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 f572bb8939..12ed4a4d53 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 b0be50a254..aafa1451da 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 @@ -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 ac715fa0b6..a27e7aa240 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; ipPrior, zAff); + + for(i=0; ipEList->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; inSrc; 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 d234f5e350..71c6c6f840 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 52b8c8ac54..f09d3b9b2a 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( inCursor ); 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=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: ** ** ( * 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; nnaType[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; nnaType[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 && inCursor ); 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 4814647fb6..c5a464b2bb 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; inOp; i++){ + for(i=addr; inOp; 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; inField; i++ ){ + u64 dummy; + offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy); + offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy); + } + + for( i=0; inField; 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; }