mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
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
This commit is contained in:
28
manifest
28
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
|
||||
|
@@ -1 +1 @@
|
||||
b55590501b5b5ada4e22d790e1a36b532de7deb7
|
||||
663a590e3086145a57af7569d8f798b6b6a8b76c
|
15
src/expr.c
15
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 <ctype.h>
|
||||
@@ -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; i<pParse->nColCache; i++){
|
||||
if( pParse->aColCache[i].iReg==iFrom ){
|
||||
pParse->aColCache[i].iReg = iTo;
|
||||
int x = pParse->aColCache[i].iReg;
|
||||
if( x>=iFrom && x<iFrom+nReg ){
|
||||
pParse->aColCache[i].iReg += iTo-iFrom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -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 <ctype.h>
|
||||
@@ -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);
|
||||
|
381
src/select.c
381
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( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
|
||||
@@ -2305,6 +2313,349 @@ multi_select_end:
|
||||
}
|
||||
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
||||
|
||||
#if 0 /****** ################ ******/
|
||||
/*
|
||||
** Code an output subroutine for a coroutine implementation of a
|
||||
** SELECT statment.
|
||||
*/
|
||||
static int outputSubroutine(
|
||||
Parse *pParse,
|
||||
SelectDest *pIn
|
||||
SelectDest *pDest
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
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:
|
||||
**
|
||||
** <selectA> <operator> <selectB> ORDER BY <orderbylist>
|
||||
**
|
||||
** <operator> is one of UNION ALL, UNION, EXCEPT, or INTERSECT. The idea
|
||||
** is to code both <selectA> and <selectB> 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 A<B.
|
||||
**
|
||||
** AeqB: Called when there is data from both coroutines and A==B.
|
||||
**
|
||||
** AgtB: Called when there is data from both coroutines and A>B.
|
||||
**
|
||||
** 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
|
||||
** <operator> 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; j<pGroupBy->nExpr; 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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
39
src/vdbe.c
39
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 <ctype.h>
|
||||
@@ -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 );
|
||||
int n = pOp->p3;
|
||||
int p1 = pOp->p1;
|
||||
int p2 = pOp->p2;
|
||||
assert( n>0 );
|
||||
assert( p1>0 );
|
||||
assert( p1+n<p->nMem );
|
||||
pIn1 = &p->aMem[p1];
|
||||
assert( p2>0 );
|
||||
assert( p2+n<p->nMem );
|
||||
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(pOp->p2, pOut);
|
||||
REGISTER_TRACE(p2++, pOut);
|
||||
pIn1++;
|
||||
pOut++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -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 <ctype.h>
|
||||
@@ -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;
|
||||
|
Reference in New Issue
Block a user