From: drh Date: Sun, 22 Jun 2008 12:37:57 +0000 (+0000) Subject: Fix a bug in the KEYINFO handling within select.c. Change the OP_Move X-Git-Tag: version-3.6.10~905 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b21e7c70f761982929ea792cd7693ee5cc8bc6d8;p=thirdparty%2Fsqlite.git Fix a bug in the KEYINFO handling within select.c. Change the OP_Move opcode to take a count and to move multiple registers. Initial code for the compound-select merge optimization is added but is incomplete and is commented out. (CVS 5272) FossilOrigin-Name: 663a590e3086145a57af7569d8f798b6b6a8b76c --- diff --git a/manifest b/manifest index 62c87e5b14..300354493d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Readded\serroneously\sdeleted\s{END}\stag\sand\sdoublechecked\s{(F,U,X)*}-{END}\stag\sbalancing.\sMinor\sdocumentation\scleanup.\sNo\schanges\sto\scode.\s(CVS\s5271) -D 2008-06-22T10:21:27 +C Fix\sa\sbug\sin\sthe\sKEYINFO\shandling\swithin\sselect.c.\s\sChange\sthe\sOP_Move\nopcode\sto\stake\sa\scount\sand\sto\smove\smultiple\sregisters.\s\sInitial\scode\sfor\nthe\scompound-select\smerge\soptimization\sis\sadded\sbut\sis\sincomplete\nand\sis\scommented\sout.\s(CVS\s5272) +D 2008-06-22T12:37:58 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -104,8 +104,8 @@ F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c F src/date.c e841168e5520bbbb2a1cbcdce7531d8b23017b4d F src/delete.c d3fc5987f2eb88f7b9549d58a5dfea079a83fe8b -F src/expr.c ecb3b23d3543427cba3e2ac12a6c6ae4bb20d39b -F src/fault.c 98922e8895358b0fd9cef49b155273f4a76d6070 +F src/expr.c bb0b5ff5fa81e2fb7563d17fb16d457bc60bd44f +F src/fault.c 3638519d1e0b82bccfafcb9f5ff491918b28f8e1 F src/func.c 1e7d9569570134ac0771a00382d9d4b41c4aa052 F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb @@ -137,15 +137,15 @@ F src/os_win.c 0b90d9a1ce18bfd2a5f3c4a6bdb13ec369c805a9 F src/pager.c e2a49872f1e15eb83895ace704c48ac8ded998ba F src/pager.h 6aa3050a3c684475a5a9dbad5ff1cebad612acba F src/parse.y 8c2c3145eebe1964eb279cb3c4e502eae28bb0fa -F src/pragma.c 70e7c865dce85fdf9df81848af2169009a56ed08 +F src/pragma.c e6c55362d164e4bc8ebc83a9a01635552d854800 F src/prepare.c 3c19149e75fbf3b08471a389f064da7302cad9c5 F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a -F src/select.c 8393c47a170923f40602622bfa59b8e7cbff9027 +F src/select.c ea3e5e233cf16f4cb43f6ec35972683ae7bc03f3 F src/shell.c a12ea645271b7876c8f080146f48e20b00d367ec F src/sqlite.h.in 60ce95e390d351f25b2105e0db9f04714e3e544c F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b -F src/sqliteInt.h 005b2f0aa10acd20435b46d4a9f84e20855c6f35 +F src/sqliteInt.h 973e5cc6db87f12eba25ae847494af57844be9bf F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58 F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822 @@ -169,7 +169,7 @@ F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f F src/test_loadext.c df8ab3a6481ddebbdf0d28ebac5d9e0790f7860f F src/test_malloc.c 27d4a2c32d2518e106db7837a3d66b0ca8c26a63 F src/test_md5.c 28209a4e2068711b5443c33104fe41f21d160071 -F src/test_mutex.c 8cfe5c56d5583e07c25c50f59c42ca0104dd24bb +F src/test_mutex.c b1433eb96520656fb3e4a218253a94ac32bd5775 F src/test_onefile.c 1f87d4a21cbfb24a7c35e4333fa0bd34d641f68d F src/test_osinst.c 867f1317bd135f942a63eab5a78da40fc70d1493 F src/test_schema.c e3f93725f7c5b2cff84a69dc4332040dfbc8f81a @@ -182,11 +182,11 @@ F src/update.c 2d7143b9014e955509cc4f323f9a9584fb898f34 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b F src/util.c 920d6d5dfdf25f7b85d2093705d8716f9b387e3b F src/vacuum.c 14eb21b480924d87e791cd8ab6fb35ac563243ef -F src/vdbe.c b733eaea9bb821b710c7ccc0a80551e1daaae733 +F src/vdbe.c 98d8d2f7a7f4624ee9fd76d53fea3b4a3d737dfa F src/vdbe.h 1246ace5511258b2192487581f23985bbc61b1be F src/vdbeInt.h 723fb796fc13346e01fb7269dcfe28f74006c5b3 F src/vdbeapi.c a7c6b8db324cf7eccff32de871dea36aa305c994 -F src/vdbeaux.c 5645351aed834221dac9f059f79021b5295a8626 +F src/vdbeaux.c eff4eed70cbf14c993df0eeacc28932853093a48 F src/vdbeblob.c 9345f6dcd675fdcfdb537d2d2f487542d9ea136a F src/vdbefifo.c c46dae1194e4277bf007144d7e5b0c0b1c24f136 F src/vdbemem.c a39a822e6ae61c4cab4a512df4a315888b206911 @@ -592,7 +592,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 3a88e3ded9c54c319b6c5b6c3d521752cb6dac6d -R 081e4d07ddd6301b200af55c59576e7c -U mihailim -Z 315faefd512ae7f85ef85a4b6143785f +P b55590501b5b5ada4e22d790e1a36b532de7deb7 +R 65180a3dac28f30f6bbb45974eb11cf2 +U drh +Z 7b4a125c9de4dedebb0132f22a9c88b3 diff --git a/manifest.uuid b/manifest.uuid index bf0c4daa25..cae6769604 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b55590501b5b5ada4e22d790e1a36b532de7deb7 \ No newline at end of file +663a590e3086145a57af7569d8f798b6b6a8b76c \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 298dbac0cf..ef88cfecc0 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.373 2008/06/05 16:47:39 danielk1977 Exp $ +** $Id: expr.c,v 1.374 2008/06/22 12:37:58 drh Exp $ */ #include "sqliteInt.h" #include @@ -2112,16 +2112,17 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){ } /* -** Generate code to moves content from one register to another. -** Keep the column cache up-to-date. +** Generate code to move content from registers iFrom...iFrom+nReg-1 +** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. */ -void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo){ +void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ int i; if( iFrom==iTo ) return; - sqlite3VdbeAddOp2(pParse->pVdbe, OP_Move, iFrom, iTo); + sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); for(i=0; inColCache; i++){ - if( pParse->aColCache[i].iReg==iFrom ){ - pParse->aColCache[i].iReg = iTo; + int x = pParse->aColCache[i].iReg; + if( x>=iFrom && xaColCache[i].iReg += iTo-iFrom; } } } diff --git a/src/fault.c b/src/fault.c index b75dc66ba7..5ede8b9009 100644 --- a/src/fault.c +++ b/src/fault.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** $Id: fault.c,v 1.9 2008/06/20 14:59:51 danielk1977 Exp $ +** $Id: fault.c,v 1.10 2008/06/22 12:37:58 drh Exp $ */ /* @@ -69,4 +69,3 @@ void sqlite3EndBenignMalloc(void){ } #endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */ - diff --git a/src/pragma.c b/src/pragma.c index 616c1f1f57..c4c0709439 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.179 2008/06/05 11:39:11 danielk1977 Exp $ +** $Id: pragma.c,v 1.180 2008/06/22 12:37:58 drh Exp $ */ #include "sqliteInt.h" #include @@ -1004,7 +1004,7 @@ void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp2(v, OP_Move, 2, 4); + sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); diff --git a/src/select.c b/src/select.c index 2de5b94e63..d072b2042a 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.432 2008/06/20 18:13:25 drh Exp $ +** $Id: select.c,v 1.433 2008/06/22 12:37:58 drh Exp $ */ #include "sqliteInt.h" @@ -425,7 +425,7 @@ static void pushOntoSorter( int regRecord = sqlite3GetTempReg(pParse); sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0); sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); - sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1); + sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); @@ -693,7 +693,7 @@ static void selectInnerLoop( if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p, regResult); }else{ - sqlite3ExprCodeMove(pParse, regResult, iParm); + sqlite3ExprCodeMove(pParse, regResult, iParm, 1); /* The LIMIT clause will jump out of the loop for us */ } break; @@ -841,7 +841,7 @@ static void generateSortTail( } case SRT_Mem: { assert( nColumn==1 ); - sqlite3ExprCodeMove(pParse, regRow, iParm); + sqlite3ExprCodeMove(pParse, regRow, iParm, 1); /* The LIMIT clause will terminate the loop for us */ break; } @@ -1668,12 +1668,6 @@ static int processOrderGroupBy( ** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return ** the number of errors seen. ** -** The processing depends on whether the SELECT is simple or compound. -** For a simple SELECT statement, evry term of the ORDER BY or GROUP BY -** clause needs to be an expression. If any expression is an integer -** constant, then that expression is replaced by the corresponding -** expression from the result set. -** ** For compound SELECT statements, every expression needs to be of ** type TK_COLUMN with a iTable value as given in the 4th parameter. ** If any expression is an integer, that becomes the column number. @@ -1873,6 +1867,15 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ +/* Forward reference */ +static int multiSelectOrderBy( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest, /* What to do with query results */ + char *aff /* If eDest is SRT_Union, the affinity string */ +); + + #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** This routine is called to process a compound query form from @@ -1920,8 +1923,6 @@ static int multiSelect( int nSetP2 = 0; /* Number of slots in aSetP2[] used */ SelectDest dest; /* Alternative data destination */ - dest = *pDest; - /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ @@ -1953,8 +1954,15 @@ static int multiSelect( goto multi_select_end; } +#if 0 + if( p->pOrderBy ){ + return multiSelectOrderBy(pParse, p, pDest, aff); + } +#endif + /* Create the destination temporary table if necessary */ + dest = *pDest; if( dest.eDest==SRT_EphemTab ){ assert( p->pEList ); assert( nSetP2pVdbe; + if( v==0 ) return; + + if( pDest->iMem==0 ){ + pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem); + pDest->nMem = nResultCol; + } + + switch( pDest->eDest ){ + /* Store the result as data using a unique key. + */ + case SRT_Table: + case SRT_EphemTab: { + int r1 = sqlite3GetTempReg(pParse); + int r2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1); + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + sqlite3ReleaseTempReg(pParse, r2); + sqlite3ReleaseTempReg(pParse, r1); + break; + } + +#ifndef SQLITE_OMIT_SUBQUERY + /* If we are creating a set for an "expr IN (SELECT ...)" construct, + ** then there should be a single item on the stack. Write this + ** item into the set table with bogus data. + */ + case SRT_Set: { + int addr2, r1; + assert( nColumn==1 ); + addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, regResult); + p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity); + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1); + sqlite3ExprCacheAffinityChange(pParse, regResult, 1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); + sqlite3ReleaseTempReg(pParse, r1); + sqlite3VdbeJumpHere(v, addr2); + break; + } + + /* If any row exist in the result set, record that fact and abort. + */ + case SRT_Exists: { + sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm); + /* The LIMIT clause will terminate the loop for us */ + break; + } + + /* If this is a scalar select that is part of an expression, then + ** store the results in the appropriate memory cell and break out + ** of the scan loop. + */ + case SRT_Mem: { + assert( nColumn==1 ); + sqlite3ExprCodeMove(pParse, regResult, iParm, 1); + /* The LIMIT clause will jump out of the loop for us */ + break; + } +#endif /* #ifndef SQLITE_OMIT_SUBQUERY */ + + /* Send the data to the callback function or to a subroutine. In the + ** case of a subroutine, the subroutine itself is responsible for + ** popping the data from the stack. + */ + case SRT_Coroutine: + case SRT_Callback: { + if( eDest==SRT_Coroutine ){ + sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine); + }else{ + sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn); + sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn); + } + break; + } + +#if !defined(SQLITE_OMIT_TRIGGER) + /* Discard the results. This is used for SELECT statements inside + ** the body of a TRIGGER. The purpose of such selects is to call + ** user-defined functions that have side effects. We do not care + ** about the actual results of the select. + */ + default: { + break; + } +#endif + } +} + +/* +** Alternative compound select code generator for cases when there +** is an ORDER BY clause. +** +** We assume a query of the following form: +** +** ORDER BY +** +** is one of UNION ALL, UNION, EXCEPT, or INTERSECT. The idea +** is to code both and with the ORDER BY clause as +** co-routines. Then run the co-routines in parallel and merge the results +** into the output. In addition to the two coroutines (called selectA and +** selectB) there are 7 subroutines: +** +** outA: Move the output of the selectA coroutine into the output +** of the compound query. +** +** outB: Move the output of the selectB coroutine into the output +** of the compound query. (Only generated for UNION and +** UNION ALL. EXCEPT and INSERTSECT never output a row that +** appears only in B.) +** +** AltB: Called when there is data from both coroutines and AB. +** +** EofA: Called when data is exhausted from selectA. +** +** EofB: Called when data is exhausted from selectB. +** +** The implementation of the latter five subroutines depend on which +** is used: +** +** +** UNION ALL UNION EXCEPT INTERSECT +** ------------- ----------------- -------------- ----------------- +** AltB: outA, nextA outA, nextA outA, nextA nextA +** +** AeqB: outA, nextA nextA nextA outA +** nextA while A==B +** +** AgtB: outB, nextB outB, nextB nextB nextB +** +** EofA: outB, nextB A<-B, outB, halt halt +** nextB while A==B +** +** EofB: outA, nextA B<-A, outA outA, nextA halt +** nextA while A==B +** +** The implementation plan is to implement the two coroutines and seven +** subroutines first, then put the control logic at the bottom. Like this: +** +** goto Init +** coA: coroutine for left query (A) +** coB: coroutine for right query (B) +** outA: output one row of A +** outB: output one row of B (UNION and UNION ALL only) +** EofA: ... +** EofB: ... +** AltB: ... +** AeqB: ... +** AgtB: ... +** Init: initialize coroutine registers +** yield coA +** if eof(A) goto EofA +** yield coB +** if eof(B) goto EofB +** Cmpr: Compare A, B +** Jump AltB, AeqB, AgtB +** End: ... +** +** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not +** actually called using Gosub and they do not Return. EofA and EofB loop +** until all data is exhausted then jump to the "end" labe. AltB, AeqB, +** and AgtB jump to either L2 or to one of EofA or EofB. +*/ +static int multiSelectOrderBy( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest, /* What to do with query results */ + 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 */ + int nCol; /* Number of columns in the result set */ + ExprList *pOrderBy; /* The ORDER BY clause on p */ + int aSetP2[2]; /* Set P2 value of these op to number of columns */ + int nSetP2 = 0; /* Number of slots in aSetP2[] used */ + SelectDest destA; /* Destination for coroutine A */ + SelectDest destB; /* Destination for coroutine B */ + int regAddrA; + int regEofA; + int regAddrB; + int regEofB; + int addrSelectA; + int addrSelectB; + int regOutA; + int regOutB; + int addrOutA; + int addrOutB; + int addrEofA; + int addrEofB; + int addrAltB; + int addrAeqB; + int addrAgtB; + int labelCmpr; + int labelEnd; + int j1, j2, j3; + + /* Patch up the ORDER BY clause */ + + pPrior = p->pPrior; + regAddrA = ++pParse->nMem; + regEofA = ++pParse->nMem; + regAddrB = ++pParse->nMem; + regEofB = ++pParse->nMem; + regOutA = ++pParse->nMem; + regOutB = ++pParse->nMem; + sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); + sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); + + j1 = sqlite3VdbeAddOp0(v, OP_Goto); + addrSelectA = sqlite3VdbeCurrentAddr(v); + VdbeNoopComment((v, "Begin coroutine for left SELECT")); + sqlite3SelectDestInit(&destA, SRT_Coroutine, 0); + sqlite3Select(); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA); + VdbeNoopComment((v, "End coroutine for left SELECT")); + + addrSelectB = sqlite3VdbeCurrentAddr(v); + VdbeNoopComment((v, "Begin coroutine for right SELECT")); + sqlite3SelectDestInit(&destB, SRT_Coroutine, 0); + sqlite3Select(); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB); + VdbeNoopComment((v, "End coroutine for right SELECT")); + + VdbeNoopComment((v, "Output routine for A")); + addrOutA = outputSubroutine(pParse, &destA, pDest); + + VdbeNoopComment((v, "Output routine for B")); + addrOutB = outputSubroutine(pParse, &destB, pDest); + + if( op==TK_EXCEPT || op==TK_INTERSECT ){ + addrEofA = iEnd; + }else{ + VdbeNoopCommment((v, "eof-A subroutine")); + addrEofA = sqlite3VdbeCurrentAddr(v); + if( op==TK_ALL ){ + j2 = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); + }else{ + assert( op==TK_UNION ); + sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); + sqlite3ExprCodeMove(pParse, destB.iMem, destA.iMem, destB.nMem); + j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); + sqlite3VdbeAddOp3(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem); + sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+1, j2); + } + } + + + if( op==TK_INTERSECT ){ + addrEofA = iEnd; + }else{ + VdbeNoopCommment((v, "eof-B subroutine")); + addrEofA = sqlite3VdbeCurrentAddr(v); + if( op==TK_ALL || op==TK_EXCEPT ){ + j2 = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); + }else{ + assert( op==TK_UNION ); + sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); + sqlite3ExprCodeMove(pParse, destA.iMem, destB.iMem, destA.nMem); + j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); + sqlite3VdbeAddOp3(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem); + sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+1, j2); + } + } + + VdbeNoopComment((v, "A-lt-B subroutine")); + addrAltB = sqlite3VdbeCurrentAddr(v); + if( op!=TK_INTERSECT ){ + sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + } + addrAeqB = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA); + sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare); + + if( op==TK_ALL ){ + addrAeqB = addrAltB; + }else if( op==TK_INTERSECT ){ + VdbeNoopComment((v, "A-eq-B subroutine")); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + j2 = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA); + sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.iMem, + pKeyInfo, P4_KEYINFO_STATIC); + j3 = sqlite3VdbeCurrentAddr(v)+1; + sqlite3VdbeAddOp3(v, OP_Jump, j3, j2, j3); + sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare); + } + + VdbeNoopComment((v, "A-gt-B subroutine")); + addrAgtB = sqlite3VdbeCurrentAddr(v); + if( op==TK_ALL || op==TK_UNION ){ + sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + } + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB); + sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare); + + sqlite3VdbeJumpHere(v, j1); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB); + sqlite3VdbeAddOp2(v, OP_Integer, addrSelectA, regAddrA); + sqlite3VdbeAddOp2(v, OP_Integer, addrSelectB, regAddrB); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB); + sqlite3VdbeResolve(v, labelCompare); + sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.iMem, + pKeyInfo, P4_KEYINFO_HANDOFF); + sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); + sqlite3VdbeResolveLabel(v, labelEnd); + +} +#endif /***** ########### *****/ + #ifndef SQLITE_OMIT_VIEW /* Forward Declarations */ static void substExprList(sqlite3*, ExprList*, int, ExprList*); @@ -3472,7 +3823,7 @@ int sqlite3Select( } } sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, - (char*)pKeyInfo, P4_KEYINFO_STATIC); + (char*)pKeyInfo, P4_KEYINFO); j1 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); @@ -3485,9 +3836,7 @@ int sqlite3Select( ** and resets the aggregate accumulator registers in preparation ** for the next GROUP BY batch. */ - for(j=0; jnExpr; j++){ - sqlite3ExprCodeMove(pParse, iBMem+j, iAMem+j); - } + sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr); sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output one row")); sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d91383d4b8..2f37042928 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.721 2008/06/20 15:24:02 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.722 2008/06/22 12:37:58 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1911,7 +1911,7 @@ void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int); -void sqlite3ExprCodeMove(Parse*, int, int); +void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprClearColumnCache(Parse*, int); void sqlite3ExprCacheAffinityChange(Parse*, int, int); int sqlite3ExprWritableRegister(Parse*,int,int); diff --git a/src/test_mutex.c b/src/test_mutex.c index ee3037e0d8..b24bd2e675 100644 --- a/src/test_mutex.c +++ b/src/test_mutex.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** $Id: test_mutex.c,v 1.3 2008/06/19 08:51:25 danielk1977 Exp $ +** $Id: test_mutex.c,v 1.4 2008/06/22 12:37:58 drh Exp $ */ #include "tcl.h" @@ -303,4 +303,3 @@ int Sqlitetest_mutex_Init(Tcl_Interp *interp){ memset(&g, 0, sizeof(g)); return SQLITE_OK; } - diff --git a/src/vdbe.c b/src/vdbe.c index eec7b37314..5bfe1f5ba6 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.752 2008/06/20 18:13:25 drh Exp $ +** $Id: vdbe.c,v 1.753 2008/06/22 12:37:58 drh Exp $ */ #include "sqliteInt.h" #include @@ -458,7 +458,7 @@ static void registerTrace(FILE *out, int iReg, Mem *p){ #endif #ifdef SQLITE_DEBUG -# define REGISTER_TRACE(R,M) if(p->trace&&R>0)registerTrace(p->trace,R,M) +# define REGISTER_TRACE(R,M) if(p->trace)registerTrace(p->trace,R,M) #else # define REGISTER_TRACE(R,M) #endif @@ -976,27 +976,36 @@ case OP_Variable: { /* out2-prerelease */ break; } -/* Opcode: Move P1 P2 * * * +/* Opcode: Move P1 P2 P3 * * ** -** Move the value in register P1 over into register P2. Register P1 -** is left holding a NULL. It is an error for P1 and P2 to be the -** same register. +** Move the values in register P1..P1+P3-1 over into +** registers P2..P2+P3-1. Registers P1..P1+P1-1 are +** left holding a NULL. It is an error for register ranges +** P1..P1+P3-1 and P2..P2+P3-1 to overlap. */ case OP_Move: { char *zMalloc; - assert( pOp->p1>0 ); - assert( pOp->p1<=p->nMem ); - pIn1 = &p->aMem[pOp->p1]; - REGISTER_TRACE(pOp->p1, pIn1); - assert( pOp->p2>0 ); - assert( pOp->p2<=p->nMem ); - pOut = &p->aMem[pOp->p2]; - assert( pOut!=pIn1 ); - zMalloc = pOut->zMalloc; - pOut->zMalloc = 0; - sqlite3VdbeMemMove(pOut, pIn1); - pIn1->zMalloc = zMalloc; - REGISTER_TRACE(pOp->p2, pOut); + int n = pOp->p3; + int p1 = pOp->p1; + int p2 = pOp->p2; + assert( n>0 ); + assert( p1>0 ); + assert( p1+nnMem ); + pIn1 = &p->aMem[p1]; + assert( p2>0 ); + assert( p2+nnMem ); + pOut = &p->aMem[p2]; + assert( p1+n<=p2 || p2+n<=p1 ); + while( n-- ){ + REGISTER_TRACE(p1++, pIn1); + zMalloc = pOut->zMalloc; + pOut->zMalloc = 0; + sqlite3VdbeMemMove(pOut, pIn1); + pIn1->zMalloc = zMalloc; + REGISTER_TRACE(p2++, pOut); + pIn1++; + pOut++; + } break; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index e139fa9716..a89a960e6d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -14,7 +14,7 @@ ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** -** $Id: vdbeaux.c,v 1.390 2008/06/20 18:13:25 drh Exp $ +** $Id: vdbeaux.c,v 1.391 2008/06/22 12:37:58 drh Exp $ */ #include "sqliteInt.h" #include @@ -548,19 +548,13 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ pKeyInfo = sqlite3Malloc( nByte ); pOp->p4.pKeyInfo = pKeyInfo; if( pKeyInfo ){ + u8 *aSortOrder; memcpy(pKeyInfo, zP4, nByte); - /* In the current implementation, P4_KEYINFO is only ever used on - ** KeyInfo structures that have no aSortOrder component. Elements - ** with an aSortOrder always use P4_KEYINFO_HANDOFF. So we do not - ** need to bother with duplicating the aSortOrder. */ - assert( pKeyInfo->aSortOrder==0 ); -#if 0 aSortOrder = pKeyInfo->aSortOrder; if( aSortOrder ){ pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField]; memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); } -#endif pOp->p4type = P4_KEYINFO; }else{ p->db->mallocFailed = 1;