mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-08 03:22:21 +03:00
The compound-select merge optimization is mostly working with this check-in.
But there are still a few problems and so the optimization is disabled by and "#if 0". This check-in is to synchronize with the other changes happening in parallel. (CVS 5291) FossilOrigin-Name: e2ba324cbcac0ba35bbde50048677e085abb092b
This commit is contained in:
22
manifest
22
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Update\sOS/2\smutex\simplementation:\smake\smethods\sstatic\sand\sdon't\suse\sthem\sby\sthe\sold\snames\sany\smore.\sHeld/Notheld\sshould\sbe\sdebug\sonly.\s(CVS\s5290)
|
C The\scompound-select\smerge\soptimization\sis\smostly\sworking\swith\sthis\scheck-in.\nBut\sthere\sare\sstill\sa\sfew\sproblems\sand\sso\sthe\soptimization\sis\sdisabled\sby\nand\s"#if\s0".\s\sThis\scheck-in\sis\sto\ssynchronize\swith\sthe\sother\schanges\shappening\nin\sparallel.\s(CVS\s5291)
|
||||||
D 2008-06-23T22:13:28
|
D 2008-06-24T00:32:35
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff
|
F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -103,14 +103,14 @@ F src/callback.c 3ba98ae46f60aa7c2c40eac7d18fe5ba9b706b83
|
|||||||
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
||||||
F src/date.c e841168e5520bbbb2a1cbcdce7531d8b23017b4d
|
F src/date.c e841168e5520bbbb2a1cbcdce7531d8b23017b4d
|
||||||
F src/delete.c d3fc5987f2eb88f7b9549d58a5dfea079a83fe8b
|
F src/delete.c d3fc5987f2eb88f7b9549d58a5dfea079a83fe8b
|
||||||
F src/expr.c bb0b5ff5fa81e2fb7563d17fb16d457bc60bd44f
|
F src/expr.c 18af707c4346de39c25d0c30a7db4c3ea449d3df
|
||||||
F src/fault.c 3638519d1e0b82bccfafcb9f5ff491918b28f8e1
|
F src/fault.c 3638519d1e0b82bccfafcb9f5ff491918b28f8e1
|
||||||
F src/func.c 1e7d9569570134ac0771a00382d9d4b41c4aa052
|
F src/func.c 1e7d9569570134ac0771a00382d9d4b41c4aa052
|
||||||
F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
|
F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
|
||||||
F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb
|
F src/hash.c eb64e48f3781100e5934f759fbe72a63a8fe78cb
|
||||||
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
||||||
F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de
|
F src/hwtime.h 745961687a65ef8918cd551c02e5ccb4b8e772de
|
||||||
F src/insert.c 93231fd0199f044bcefda3d857420f4d377e4056
|
F src/insert.c 4656c5231059d8f40a5bbe21a28a9344c07a49bd
|
||||||
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
|
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
|
||||||
F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df
|
F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df
|
||||||
F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3
|
F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3
|
||||||
@@ -140,11 +140,11 @@ F src/pragma.c e6c55362d164e4bc8ebc83a9a01635552d854800
|
|||||||
F src/prepare.c aba51dad52308e3d9d2074d8ff4e612e7f1cab51
|
F src/prepare.c aba51dad52308e3d9d2074d8ff4e612e7f1cab51
|
||||||
F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e
|
F src/printf.c 8b063da9dcde26b7c500a01444b718d86f21bc6e
|
||||||
F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a
|
F src/random.c 5c754319d38abdd6acd74601ee0105504adc508a
|
||||||
F src/select.c ea3e5e233cf16f4cb43f6ec35972683ae7bc03f3
|
F src/select.c 1ebcd83ab51be47f31b2ec93daad844baf3b0788
|
||||||
F src/shell.c 61fa61932ed52825720ebfd3f8381b8d550ef766
|
F src/shell.c 61fa61932ed52825720ebfd3f8381b8d550ef766
|
||||||
F src/sqlite.h.in 6a80d00621a43271f01c77eb42bbf57e0f52051b
|
F src/sqlite.h.in 6a80d00621a43271f01c77eb42bbf57e0f52051b
|
||||||
F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b
|
F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b
|
||||||
F src/sqliteInt.h 0129e546b43a06844d1d66fd9d9b3090676d0873
|
F src/sqliteInt.h ec8e71249994b8a5b23b1a098a576c02e8548244
|
||||||
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
||||||
F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58
|
F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58
|
||||||
F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
|
F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
|
||||||
@@ -438,7 +438,7 @@ F test/rtree.test a8404a59bbc3a7827db9bfb334790c852f0391b3
|
|||||||
F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
|
F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
|
||||||
F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c
|
F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c
|
||||||
F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
|
F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
|
||||||
F test/select1.test 2f011e7aa0accada53795bc95f00d268a3811bd4
|
F test/select1.test 64f6231c75b01ec30c88dd9d45d0979169ee4d95
|
||||||
F test/select2.test 06a2660de57673e2d076c29c0fd73f961a930f87
|
F test/select2.test 06a2660de57673e2d076c29c0fd73f961a930f87
|
||||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||||
F test/select4.test 7cc135c8343e6e433bdad185de6a720b112c40e7
|
F test/select4.test 7cc135c8343e6e433bdad185de6a720b112c40e7
|
||||||
@@ -592,7 +592,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P bf2e283d6fd40cabe55864b06b502524eb8a3b07
|
P d92418ca502f5f58dc968668e11c42955a7b1e52
|
||||||
R bfadbc404a2d8b31ffee6a81899b30a6
|
R f88ace7929fab768ff8007a473e6b665
|
||||||
U pweilbacher
|
U drh
|
||||||
Z 4ec4b9feb6cdd59c7ef6420f4a9a5810
|
Z 9ed7972d77404d7a52eef908bd3410d8
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
d92418ca502f5f58dc968668e11c42955a7b1e52
|
e2ba324cbcac0ba35bbde50048677e085abb092b
|
||||||
56
src/expr.c
56
src/expr.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.374 2008/06/22 12:37:58 drh Exp $
|
** $Id: expr.c,v 1.375 2008/06/24 00:32:35 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -756,8 +756,8 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p){
|
|||||||
pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
|
pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
|
||||||
pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
|
pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
|
||||||
pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
|
pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
|
||||||
pNew->iLimit = -1;
|
pNew->iLimit = 0;
|
||||||
pNew->iOffset = -1;
|
pNew->iOffset = 0;
|
||||||
pNew->isResolved = p->isResolved;
|
pNew->isResolved = p->isResolved;
|
||||||
pNew->isAgg = p->isAgg;
|
pNew->isAgg = p->isAgg;
|
||||||
pNew->usesEphm = 0;
|
pNew->usesEphm = 0;
|
||||||
@@ -1018,27 +1018,35 @@ int sqlite3ExprIsConstantOrFunction(Expr *p){
|
|||||||
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
|
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
|
||||||
*/
|
*/
|
||||||
int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
||||||
switch( p->op ){
|
int rc = 0;
|
||||||
case TK_INTEGER: {
|
if( p->flags & EP_IntValue ){
|
||||||
if( sqlite3GetInt32((char*)p->token.z, pValue) ){
|
*pValue = p->iTable;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
switch( p->op ){
|
||||||
|
case TK_INTEGER: {
|
||||||
|
rc = sqlite3GetInt32((char*)p->token.z, pValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_UPLUS: {
|
case TK_UPLUS: {
|
||||||
return sqlite3ExprIsInteger(p->pLeft, pValue);
|
rc = sqlite3ExprIsInteger(p->pLeft, pValue);
|
||||||
}
|
}
|
||||||
case TK_UMINUS: {
|
case TK_UMINUS: {
|
||||||
int v;
|
int v;
|
||||||
if( sqlite3ExprIsInteger(p->pLeft, &v) ){
|
if( sqlite3ExprIsInteger(p->pLeft, &v) ){
|
||||||
*pValue = -v;
|
*pValue = -v;
|
||||||
return 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return 0;
|
if( rc ){
|
||||||
|
p->op = TK_INTEGER;
|
||||||
|
p->flags |= EP_IntValue;
|
||||||
|
p->iTable = *pValue;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1986,10 +1994,15 @@ static void codeReal(Vdbe *v, const char *z, int n, int negateFlag, int iMem){
|
|||||||
** z[n] character is guaranteed to be something that does not look
|
** z[n] character is guaranteed to be something that does not look
|
||||||
** like the continuation of the number.
|
** like the continuation of the number.
|
||||||
*/
|
*/
|
||||||
static void codeInteger(Vdbe *v, const char *z, int n, int negFlag, int iMem){
|
static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
|
||||||
assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed );
|
const char *z;
|
||||||
if( z ){
|
if( pExpr->flags & EP_IntValue ){
|
||||||
|
int i = pExpr->iTable;
|
||||||
|
if( negFlag ) i = -i;
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
|
||||||
|
}else if( (z = (char*)pExpr->token.z)!=0 ){
|
||||||
int i;
|
int i;
|
||||||
|
int n = pExpr->token.n;
|
||||||
assert( !isdigit(z[n]) );
|
assert( !isdigit(z[n]) );
|
||||||
if( sqlite3GetInt32(z, &i) ){
|
if( sqlite3GetInt32(z, &i) ){
|
||||||
if( negFlag ) i = -i;
|
if( negFlag ) i = -i;
|
||||||
@@ -2127,6 +2140,18 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate code to copy content from registers iFrom...iFrom+nReg-1
|
||||||
|
** over to iTo..iTo+nReg-1.
|
||||||
|
*/
|
||||||
|
void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||||
|
int i;
|
||||||
|
if( iFrom==iTo ) return;
|
||||||
|
for(i=0; i<nReg; i++){
|
||||||
|
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return true if any register in the range iFrom..iTo (inclusive)
|
** Return true if any register in the range iFrom..iTo (inclusive)
|
||||||
** is used as part of the column cache.
|
** is used as part of the column cache.
|
||||||
@@ -2246,7 +2271,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_INTEGER: {
|
case TK_INTEGER: {
|
||||||
codeInteger(v, (char*)pExpr->token.z, pExpr->token.n, 0, target);
|
codeInteger(v, pExpr, 0, target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_FLOAT: {
|
case TK_FLOAT: {
|
||||||
@@ -2384,11 +2409,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
Expr *pLeft = pExpr->pLeft;
|
Expr *pLeft = pExpr->pLeft;
|
||||||
assert( pLeft );
|
assert( pLeft );
|
||||||
if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
|
if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
|
||||||
Token *p = &pLeft->token;
|
|
||||||
if( pLeft->op==TK_FLOAT ){
|
if( pLeft->op==TK_FLOAT ){
|
||||||
codeReal(v, (char*)p->z, p->n, 1, target);
|
codeReal(v, (char*)pLeft->token.z, pLeft->token.n, 1, target);
|
||||||
}else{
|
}else{
|
||||||
codeInteger(v, (char*)p->z, p->n, 1, target);
|
codeInteger(v, pLeft, 1, target);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
regFree1 = r1 = sqlite3GetTempReg(pParse);
|
regFree1 = r1 = sqlite3GetTempReg(pParse);
|
||||||
|
|||||||
13
src/insert.c
13
src/insert.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** to handle INSERT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: insert.c,v 1.241 2008/06/20 15:24:02 drh Exp $
|
** $Id: insert.c,v 1.242 2008/06/24 00:32:35 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -523,10 +523,9 @@ void sqlite3Insert(
|
|||||||
regEof = ++pParse->nMem;
|
regEof = ++pParse->nMem;
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
||||||
VdbeComment((v, "SELECT eof flag"));
|
VdbeComment((v, "SELECT eof flag"));
|
||||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, 0);
|
sqlite3SelectDestInit(&dest, SRT_Coroutine, ++pParse->nMem);
|
||||||
dest.regCoroutine = ++pParse->nMem;
|
|
||||||
addrSelect = sqlite3VdbeCurrentAddr(v)+2;
|
addrSelect = sqlite3VdbeCurrentAddr(v)+2;
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.regCoroutine);
|
sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.iParm);
|
||||||
j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||||
VdbeComment((v, "Jump over SELECT coroutine"));
|
VdbeComment((v, "Jump over SELECT coroutine"));
|
||||||
|
|
||||||
@@ -536,7 +535,7 @@ void sqlite3Insert(
|
|||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine); /* yield X */
|
sqlite3VdbeAddOp1(v, OP_Yield, dest.iParm); /* yield X */
|
||||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
||||||
VdbeComment((v, "End of SELECT coroutine"));
|
VdbeComment((v, "End of SELECT coroutine"));
|
||||||
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
||||||
@@ -580,7 +579,7 @@ void sqlite3Insert(
|
|||||||
regRec = sqlite3GetTempReg(pParse);
|
regRec = sqlite3GetTempReg(pParse);
|
||||||
regRowid = sqlite3GetTempReg(pParse);
|
regRowid = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);
|
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iParm);
|
||||||
addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
||||||
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
|
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
|
||||||
@@ -725,7 +724,7 @@ void sqlite3Insert(
|
|||||||
** goto C
|
** goto C
|
||||||
** D: ...
|
** D: ...
|
||||||
*/
|
*/
|
||||||
addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.regCoroutine);
|
addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iParm);
|
||||||
addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
418
src/select.c
418
src/select.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.433 2008/06/22 12:37:58 drh Exp $
|
** $Id: select.c,v 1.434 2008/06/24 00:32:36 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -39,7 +39,6 @@ static void clearSelect(Select *p){
|
|||||||
void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
|
void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
|
||||||
pDest->eDest = eDest;
|
pDest->eDest = eDest;
|
||||||
pDest->iParm = iParm;
|
pDest->iParm = iParm;
|
||||||
pDest->regCoroutine = 0;
|
|
||||||
pDest->affinity = 0;
|
pDest->affinity = 0;
|
||||||
pDest->iMem = 0;
|
pDest->iMem = 0;
|
||||||
pDest->nMem = 0;
|
pDest->nMem = 0;
|
||||||
@@ -85,8 +84,6 @@ Select *sqlite3SelectNew(
|
|||||||
assert( pOffset==0 || pLimit!=0 );
|
assert( pOffset==0 || pLimit!=0 );
|
||||||
pNew->pLimit = pLimit;
|
pNew->pLimit = pLimit;
|
||||||
pNew->pOffset = pOffset;
|
pNew->pOffset = pOffset;
|
||||||
pNew->iLimit = -1;
|
|
||||||
pNew->iOffset = -1;
|
|
||||||
pNew->addrOpenEphm[0] = -1;
|
pNew->addrOpenEphm[0] = -1;
|
||||||
pNew->addrOpenEphm[1] = -1;
|
pNew->addrOpenEphm[1] = -1;
|
||||||
pNew->addrOpenEphm[2] = -1;
|
pNew->addrOpenEphm[2] = -1;
|
||||||
@@ -430,7 +427,7 @@ static void pushOntoSorter(
|
|||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
|
||||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||||
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
||||||
if( pSelect->iLimit>=0 ){
|
if( pSelect->iLimit ){
|
||||||
int addr1, addr2;
|
int addr1, addr2;
|
||||||
int iLimit;
|
int iLimit;
|
||||||
if( pSelect->pOffset ){
|
if( pSelect->pOffset ){
|
||||||
@@ -445,7 +442,7 @@ static void pushOntoSorter(
|
|||||||
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
|
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
|
||||||
sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
|
sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
|
||||||
sqlite3VdbeJumpHere(v, addr2);
|
sqlite3VdbeJumpHere(v, addr2);
|
||||||
pSelect->iLimit = -1;
|
pSelect->iLimit = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +454,7 @@ static void codeOffset(
|
|||||||
Select *p, /* The SELECT statement being coded */
|
Select *p, /* The SELECT statement being coded */
|
||||||
int iContinue /* Jump here to skip the current record */
|
int iContinue /* Jump here to skip the current record */
|
||||||
){
|
){
|
||||||
if( p->iOffset>=0 && iContinue!=0 ){
|
if( p->iOffset && iContinue!=0 ){
|
||||||
int addr;
|
int addr;
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
|
||||||
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
|
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
|
||||||
@@ -712,7 +709,7 @@ static void selectInnerLoop(
|
|||||||
pushOntoSorter(pParse, pOrderBy, p, r1);
|
pushOntoSorter(pParse, pOrderBy, p, r1);
|
||||||
sqlite3ReleaseTempReg(pParse, r1);
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}else if( eDest==SRT_Coroutine ){
|
}else if( eDest==SRT_Coroutine ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
|
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
|
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
|
||||||
sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
|
sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
|
||||||
@@ -735,7 +732,7 @@ static void selectInnerLoop(
|
|||||||
|
|
||||||
/* Jump to the end of the loop if the LIMIT is reached.
|
/* Jump to the end of the loop if the LIMIT is reached.
|
||||||
*/
|
*/
|
||||||
if( p->iLimit>=0 && pOrderBy==0 ){
|
if( p->iLimit && pOrderBy==0 ){
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
||||||
sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
|
sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
|
||||||
}
|
}
|
||||||
@@ -859,7 +856,7 @@ static void generateSortTail(
|
|||||||
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn);
|
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn);
|
||||||
sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn);
|
sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn);
|
||||||
}else if( eDest==SRT_Coroutine ){
|
}else if( eDest==SRT_Coroutine ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
|
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -873,7 +870,7 @@ static void generateSortTail(
|
|||||||
|
|
||||||
/* Jump to the end of the loop when the LIMIT is reached
|
/* Jump to the end of the loop when the LIMIT is reached
|
||||||
*/
|
*/
|
||||||
if( p->iLimit>=0 ){
|
if( p->iLimit ){
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
||||||
sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, brk);
|
sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, brk);
|
||||||
}
|
}
|
||||||
@@ -1508,9 +1505,9 @@ static int prepSelectStmt(Parse *pParse, Select *p){
|
|||||||
** pE is a pointer to an expression which is a single term in
|
** pE is a pointer to an expression which is a single term in
|
||||||
** ORDER BY or GROUP BY clause.
|
** ORDER BY or GROUP BY clause.
|
||||||
**
|
**
|
||||||
** If pE evaluates to an integer constant i, then return i.
|
** At the point this routine is called, we already know that the
|
||||||
** This is an indication to the caller that it should sort
|
** ORDER BY term is not an integer index into the result set. That
|
||||||
** by the i-th column of the result set.
|
** casee is handled by the calling routine.
|
||||||
**
|
**
|
||||||
** If pE is a well-formed expression and the SELECT statement
|
** If pE is a well-formed expression and the SELECT statement
|
||||||
** is not compound, then return 0. This indicates to the
|
** is not compound, then return 0. This indicates to the
|
||||||
@@ -1535,20 +1532,8 @@ static int matchOrderByTermToExprList(
|
|||||||
ExprList *pEList; /* The columns of the result set */
|
ExprList *pEList; /* The columns of the result set */
|
||||||
NameContext nc; /* Name context for resolving pE */
|
NameContext nc; /* Name context for resolving pE */
|
||||||
|
|
||||||
|
assert( sqlite3ExprIsInteger(pE, &i)==0 );
|
||||||
/* If the term is an integer constant, return the value of that
|
|
||||||
** constant */
|
|
||||||
pEList = pSelect->pEList;
|
pEList = pSelect->pEList;
|
||||||
if( sqlite3ExprIsInteger(pE, &i) ){
|
|
||||||
if( i<=0 ){
|
|
||||||
/* If i is too small, make it too big. That way the calling
|
|
||||||
** function still sees a value that is out of range, but does
|
|
||||||
** not confuse the column number with 0 or -1 result code.
|
|
||||||
*/
|
|
||||||
i = pEList->nExpr+1;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the term is a simple identifier that try to match that identifier
|
/* If the term is a simple identifier that try to match that identifier
|
||||||
** against a column name in the result set.
|
** against a column name in the result set.
|
||||||
@@ -1638,17 +1623,20 @@ static int processOrderGroupBy(
|
|||||||
for(i=0; i<pOrderBy->nExpr; i++){
|
for(i=0; i<pOrderBy->nExpr; i++){
|
||||||
int iCol;
|
int iCol;
|
||||||
Expr *pE = pOrderBy->a[i].pExpr;
|
Expr *pE = pOrderBy->a[i].pExpr;
|
||||||
iCol = matchOrderByTermToExprList(pParse, pSelect, pE, i+1, 0, pHasAgg);
|
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||||
if( iCol<0 ){
|
if( iCol<=0 || iCol>pEList->nExpr ){
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if( iCol>pEList->nExpr ){
|
|
||||||
const char *zType = isOrder ? "ORDER" : "GROUP";
|
const char *zType = isOrder ? "ORDER" : "GROUP";
|
||||||
sqlite3ErrorMsg(pParse,
|
sqlite3ErrorMsg(pParse,
|
||||||
"%r %s BY term out of range - should be "
|
"%r %s BY term out of range - should be "
|
||||||
"between 1 and %d", i+1, zType, pEList->nExpr);
|
"between 1 and %d", i+1, zType, pEList->nExpr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
iCol = matchOrderByTermToExprList(pParse, pSelect, pE, i+1, 0, pHasAgg);
|
||||||
|
if( iCol<0 ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if( iCol>0 ){
|
if( iCol>0 ){
|
||||||
CollSeq *pColl = pE->pColl;
|
CollSeq *pColl = pE->pColl;
|
||||||
int flags = pE->flags & EP_ExpCollate;
|
int flags = pE->flags & EP_ExpCollate;
|
||||||
@@ -1668,11 +1656,11 @@ static int processOrderGroupBy(
|
|||||||
** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return
|
** Analyze and ORDER BY or GROUP BY clause in a SELECT statement. Return
|
||||||
** the number of errors seen.
|
** the number of errors seen.
|
||||||
**
|
**
|
||||||
** For compound SELECT statements, every expression needs to be of
|
** If iTable>0 then make the N-th term of the ORDER BY clause refer to
|
||||||
** type TK_COLUMN with a iTable value as given in the 4th parameter.
|
** the N-th column of table iTable.
|
||||||
** If any expression is an integer, that becomes the column number.
|
**
|
||||||
** Otherwise, match the expression against result set columns from
|
** If iTable==0 then transform each term of the ORDER BY clause to refer
|
||||||
** the left-most SELECT.
|
** to a column of the result set by number.
|
||||||
*/
|
*/
|
||||||
static int processCompoundOrderBy(
|
static int processCompoundOrderBy(
|
||||||
Parse *pParse, /* Parsing context. Leave error messages here */
|
Parse *pParse, /* Parsing context. Leave error messages here */
|
||||||
@@ -1702,11 +1690,23 @@ static int processCompoundOrderBy(
|
|||||||
}
|
}
|
||||||
while( pSelect && moreToDo ){
|
while( pSelect && moreToDo ){
|
||||||
moreToDo = 0;
|
moreToDo = 0;
|
||||||
|
pEList = pSelect->pEList;
|
||||||
|
if( pEList==0 ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
for(i=0; i<pOrderBy->nExpr; i++){
|
for(i=0; i<pOrderBy->nExpr; i++){
|
||||||
int iCol = -1;
|
int iCol = -1;
|
||||||
Expr *pE, *pDup;
|
Expr *pE, *pDup;
|
||||||
if( pOrderBy->a[i].done ) continue;
|
if( pOrderBy->a[i].done ) continue;
|
||||||
pE = pOrderBy->a[i].pExpr;
|
pE = pOrderBy->a[i].pExpr;
|
||||||
|
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||||
|
if( iCol<0 || iCol>pEList->nExpr ){
|
||||||
|
sqlite3ErrorMsg(pParse,
|
||||||
|
"%r ORDER BY term out of range - should be "
|
||||||
|
"between 1 and %d", i+1, pEList->nExpr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
pDup = sqlite3ExprDup(db, pE);
|
pDup = sqlite3ExprDup(db, pE);
|
||||||
if( !db->mallocFailed ){
|
if( !db->mallocFailed ){
|
||||||
assert(pDup);
|
assert(pDup);
|
||||||
@@ -1716,22 +1716,19 @@ static int processCompoundOrderBy(
|
|||||||
if( iCol<0 ){
|
if( iCol<0 ){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
pEList = pSelect->pEList;
|
|
||||||
if( pEList==0 ){
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if( iCol>pEList->nExpr ){
|
|
||||||
sqlite3ErrorMsg(pParse,
|
|
||||||
"%r ORDER BY term out of range - should be "
|
|
||||||
"between 1 and %d", i+1, pEList->nExpr);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
if( iCol>0 ){
|
if( iCol>0 ){
|
||||||
|
if( iTable ){
|
||||||
pE->op = TK_COLUMN;
|
pE->op = TK_COLUMN;
|
||||||
pE->iTable = iTable;
|
pE->iTable = iTable;
|
||||||
pE->iAgg = -1;
|
pE->iAgg = -1;
|
||||||
pE->iColumn = iCol-1;
|
pE->iColumn = iCol-1;
|
||||||
pE->pTab = 0;
|
pE->pTab = 0;
|
||||||
|
}else{
|
||||||
|
pE->op = TK_INTEGER;
|
||||||
|
pE->flags |= EP_IntValue;
|
||||||
|
pE->iTable = iCol;
|
||||||
|
}
|
||||||
pOrderBy->a[i].done = 1;
|
pOrderBy->a[i].done = 1;
|
||||||
}else{
|
}else{
|
||||||
moreToDo = 1;
|
moreToDo = 1;
|
||||||
@@ -1989,7 +1986,7 @@ static int multiSelect(
|
|||||||
p->pPrior = 0;
|
p->pPrior = 0;
|
||||||
p->iLimit = pPrior->iLimit;
|
p->iLimit = pPrior->iLimit;
|
||||||
p->iOffset = pPrior->iOffset;
|
p->iOffset = pPrior->iOffset;
|
||||||
if( p->iLimit>=0 ){
|
if( p->iLimit ){
|
||||||
addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit);
|
addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit);
|
||||||
VdbeComment((v, "Jump ahead if LIMIT reached"));
|
VdbeComment((v, "Jump ahead if LIMIT reached"));
|
||||||
}
|
}
|
||||||
@@ -2075,8 +2072,8 @@ static int multiSelect(
|
|||||||
sqlite3ExprDelete(p->pLimit);
|
sqlite3ExprDelete(p->pLimit);
|
||||||
p->pLimit = pLimit;
|
p->pLimit = pLimit;
|
||||||
p->pOffset = pOffset;
|
p->pOffset = pOffset;
|
||||||
p->iLimit = -1;
|
p->iLimit = 0;
|
||||||
p->iOffset = -1;
|
p->iOffset = 0;
|
||||||
if( rc ){
|
if( rc ){
|
||||||
goto multi_select_end;
|
goto multi_select_end;
|
||||||
}
|
}
|
||||||
@@ -2313,23 +2310,26 @@ multi_select_end:
|
|||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
||||||
|
|
||||||
#if 0 /****** ################ ******/
|
|
||||||
/*
|
/*
|
||||||
** Code an output subroutine for a coroutine implementation of a
|
** Code an output subroutine for a coroutine implementation of a
|
||||||
** SELECT statment.
|
** SELECT statment.
|
||||||
*/
|
*/
|
||||||
static int outputSubroutine(
|
static int outputSubroutine(
|
||||||
Parse *pParse,
|
Parse *pParse, /* Parsing context */
|
||||||
SelectDest *pIn
|
Select *p, /* The SELECT statement */
|
||||||
SelectDest *pDest
|
SelectDest *pIn, /* Coroutine supplying data */
|
||||||
|
SelectDest *pDest, /* Where to send the data */
|
||||||
|
int regReturn, /* The return address register */
|
||||||
|
int iBreak /* Jump here if we hit the LIMIT */
|
||||||
){
|
){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
if( v==0 ) return;
|
int iContinue;
|
||||||
|
int addr;
|
||||||
|
if( v==0 ) return 0;
|
||||||
|
|
||||||
if( pDest->iMem==0 ){
|
addr = sqlite3VdbeCurrentAddr(v);
|
||||||
pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem);
|
iContinue = sqlite3VdbeMakeLabel(v);
|
||||||
pDest->nMem = nResultCol;
|
codeOffset(v, p, iContinue);
|
||||||
}
|
|
||||||
|
|
||||||
switch( pDest->eDest ){
|
switch( pDest->eDest ){
|
||||||
/* Store the result as data using a unique key.
|
/* Store the result as data using a unique key.
|
||||||
@@ -2338,9 +2338,9 @@ static int outputSubroutine(
|
|||||||
case SRT_EphemTab: {
|
case SRT_EphemTab: {
|
||||||
int r1 = sqlite3GetTempReg(pParse);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
int r2 = sqlite3GetTempReg(pParse);
|
int r2 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iMem, pIn->nMem, r1);
|
||||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
|
sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iParm, r2);
|
||||||
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
|
sqlite3VdbeAddOp3(v, OP_Insert, pDest->iParm, r1, r2);
|
||||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||||
sqlite3ReleaseTempReg(pParse, r2);
|
sqlite3ReleaseTempReg(pParse, r2);
|
||||||
sqlite3ReleaseTempReg(pParse, r1);
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
@@ -2354,13 +2354,14 @@ static int outputSubroutine(
|
|||||||
*/
|
*/
|
||||||
case SRT_Set: {
|
case SRT_Set: {
|
||||||
int addr2, r1;
|
int addr2, r1;
|
||||||
assert( nColumn==1 );
|
assert( pIn->nMem==1 );
|
||||||
addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, regResult);
|
addr2 = sqlite3VdbeAddOp1(v, OP_IsNull, pIn->iMem);
|
||||||
p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity);
|
p->affinity =
|
||||||
|
sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affinity);
|
||||||
r1 = sqlite3GetTempReg(pParse);
|
r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1);
|
sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iMem, 1, r1, &p->affinity, 1);
|
||||||
sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
|
sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, 1);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iParm, r1);
|
||||||
sqlite3ReleaseTempReg(pParse, r1);
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
sqlite3VdbeJumpHere(v, addr2);
|
sqlite3VdbeJumpHere(v, addr2);
|
||||||
break;
|
break;
|
||||||
@@ -2369,7 +2370,7 @@ static int outputSubroutine(
|
|||||||
/* If any row exist in the result set, record that fact and abort.
|
/* If any row exist in the result set, record that fact and abort.
|
||||||
*/
|
*/
|
||||||
case SRT_Exists: {
|
case SRT_Exists: {
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm);
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iParm);
|
||||||
/* The LIMIT clause will terminate the loop for us */
|
/* The LIMIT clause will terminate the loop for us */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2379,8 +2380,8 @@ static int outputSubroutine(
|
|||||||
** of the scan loop.
|
** of the scan loop.
|
||||||
*/
|
*/
|
||||||
case SRT_Mem: {
|
case SRT_Mem: {
|
||||||
assert( nColumn==1 );
|
assert( pIn->nMem==1 );
|
||||||
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
|
sqlite3ExprCodeMove(pParse, pIn->iMem, pDest->iParm, 1);
|
||||||
/* The LIMIT clause will jump out of the loop for us */
|
/* The LIMIT clause will jump out of the loop for us */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2390,14 +2391,19 @@ static int outputSubroutine(
|
|||||||
** case of a subroutine, the subroutine itself is responsible for
|
** case of a subroutine, the subroutine itself is responsible for
|
||||||
** popping the data from the stack.
|
** popping the data from the stack.
|
||||||
*/
|
*/
|
||||||
case SRT_Coroutine:
|
case SRT_Coroutine: {
|
||||||
case SRT_Callback: {
|
if( pDest->iMem==0 ){
|
||||||
if( eDest==SRT_Coroutine ){
|
pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, pDest->regCoroutine);
|
pDest->nMem = pIn->nMem;
|
||||||
}else{
|
|
||||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nColumn);
|
|
||||||
sqlite3ExprCacheAffinityChange(pParse, regResult, nColumn);
|
|
||||||
}
|
}
|
||||||
|
sqlite3ExprCodeMove(pParse, pIn->iMem, pDest->iMem, pDest->nMem);
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SRT_Callback: {
|
||||||
|
sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iMem, pIn->nMem);
|
||||||
|
sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, pIn->nMem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2412,6 +2418,24 @@ static int outputSubroutine(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Jump to the end of the loop if the LIMIT is reached.
|
||||||
|
*/
|
||||||
|
if( p->iLimit ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance the coroutine to its next value.
|
||||||
|
*/
|
||||||
|
sqlite3VdbeResolveLabel(v, iContinue);
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Yield, pIn->iParm);
|
||||||
|
|
||||||
|
/* Generate the subroutine return
|
||||||
|
*/
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Return, regReturn);
|
||||||
|
|
||||||
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2498,37 +2522,74 @@ static int multiSelectOrderBy(
|
|||||||
SelectDest *pDest, /* What to do with query results */
|
SelectDest *pDest, /* What to do with query results */
|
||||||
char *aff /* If eDest is SRT_Union, the affinity string */
|
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 */
|
Select *pPrior; /* Another SELECT immediately to our left */
|
||||||
Vdbe *v; /* Generate code to this VDBE */
|
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 destA; /* Destination for coroutine A */
|
||||||
SelectDest destB; /* Destination for coroutine B */
|
SelectDest destB; /* Destination for coroutine B */
|
||||||
int regAddrA;
|
int regAddrA; /* Address register for select-A coroutine */
|
||||||
int regEofA;
|
int regEofA; /* Flag to indicate when select-A is complete */
|
||||||
int regAddrB;
|
int regAddrB; /* Address register for select-B coroutine */
|
||||||
int regEofB;
|
int regEofB; /* Flag to indicate when select-B is complete */
|
||||||
int addrSelectA;
|
int addrSelectA; /* Address of the select-A coroutine */
|
||||||
int addrSelectB;
|
int addrSelectB; /* Address of the select-B coroutine */
|
||||||
int regOutA;
|
int regOutA; /* Address register for the output-A subroutine */
|
||||||
int regOutB;
|
int regOutB; /* Address register for the output-B subroutine */
|
||||||
int addrOutA;
|
int addrOutA; /* Address of the output-A subroutine */
|
||||||
int addrOutB;
|
int addrOutB; /* Address of the output-B subroutine */
|
||||||
int addrEofA;
|
int addrEofA; /* Address of the select-A-exhausted subroutine */
|
||||||
int addrEofB;
|
int addrEofB; /* Address of the select-B-exhausted subroutine */
|
||||||
int addrAltB;
|
int addrAltB; /* Address of the A<B subroutine */
|
||||||
int addrAeqB;
|
int addrAeqB; /* Address of the A==B subroutine */
|
||||||
int addrAgtB;
|
int addrAgtB; /* Address of the A>B subroutine */
|
||||||
int labelCmpr;
|
int regLimitA; /* Limit register for select-A */
|
||||||
int labelEnd;
|
int regLimitB; /* Limit register for select-A */
|
||||||
int j1, j2, j3;
|
int savedLimit; /* Saved value of p->iLimit */
|
||||||
|
int savedOffset; /* Saved value of p->iOffset */
|
||||||
|
int labelCmpr; /* Label for the start of the merge algorithm */
|
||||||
|
int labelEnd; /* Label for the end of the overall SELECT stmt */
|
||||||
|
int j1, j2, j3; /* Jump instructions that get retargetted */
|
||||||
|
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
|
||||||
|
KeyInfo *pKeyInfo; /* Type data for comparisons */
|
||||||
|
int p4type; /* P4 type used for pKeyInfo */
|
||||||
|
u8 NotUsed; /* Dummy variable */
|
||||||
|
|
||||||
/* Patch up the ORDER BY clause */
|
assert( p->pOrderBy!=0 );
|
||||||
|
v = pParse->pVdbe;
|
||||||
|
if( v==0 ) return SQLITE_NOMEM;
|
||||||
|
labelEnd = sqlite3VdbeMakeLabel(v);
|
||||||
|
labelCmpr = sqlite3VdbeMakeLabel(v);
|
||||||
|
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
|
||||||
|
p4type = P4_KEYINFO_HANDOFF;
|
||||||
|
|
||||||
|
/* Patch up the ORDER BY clause
|
||||||
|
*/
|
||||||
|
op = p->op;
|
||||||
pPrior = p->pPrior;
|
pPrior = p->pPrior;
|
||||||
|
assert( pPrior->pOrderBy==0 );
|
||||||
|
if( processCompoundOrderBy(pParse, p, 0) ){
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy);
|
||||||
|
|
||||||
|
/* Separate the left and the right query from one another
|
||||||
|
*/
|
||||||
|
p->pPrior = 0;
|
||||||
|
pPrior->pRightmost = 0;
|
||||||
|
processOrderGroupBy(pParse, p, p->pOrderBy, 1, &NotUsed);
|
||||||
|
processOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, 1, &NotUsed);
|
||||||
|
|
||||||
|
/* Compute the limit registers */
|
||||||
|
computeLimitRegisters(pParse, p, labelEnd);
|
||||||
|
if( p->iLimit ){
|
||||||
|
regLimitA = ++pParse->nMem;
|
||||||
|
regLimitB = ++pParse->nMem;
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit,
|
||||||
|
regLimitA);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Copy, regLimitA, regLimitB);
|
||||||
|
}else{
|
||||||
|
regLimitA = regLimitB = 0;
|
||||||
|
}
|
||||||
|
|
||||||
regAddrA = ++pParse->nMem;
|
regAddrA = ++pParse->nMem;
|
||||||
regEofA = ++pParse->nMem;
|
regEofA = ++pParse->nMem;
|
||||||
regAddrB = ++pParse->nMem;
|
regAddrB = ++pParse->nMem;
|
||||||
@@ -2538,123 +2599,194 @@ static int multiSelectOrderBy(
|
|||||||
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
||||||
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
||||||
|
|
||||||
|
/* Jump past the various subroutines and coroutines to the main
|
||||||
|
** merge loop
|
||||||
|
*/
|
||||||
j1 = sqlite3VdbeAddOp0(v, OP_Goto);
|
j1 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
addrSelectA = sqlite3VdbeCurrentAddr(v);
|
addrSelectA = sqlite3VdbeCurrentAddr(v);
|
||||||
|
|
||||||
|
/* Generate a coroutine to evaluate the SELECT statement to the
|
||||||
|
** left of the compound operator - the "A" select. */
|
||||||
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
|
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
|
||||||
sqlite3SelectDestInit(&destA, SRT_Coroutine, 0);
|
pPrior->iLimit = regLimitA;
|
||||||
sqlite3Select();
|
sqlite3Select(pParse, pPrior, &destA, 0, 0, 0, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
|
||||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA);
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||||
VdbeNoopComment((v, "End coroutine for left SELECT"));
|
VdbeNoopComment((v, "End coroutine for left SELECT"));
|
||||||
|
|
||||||
|
/* Generate a coroutine to evaluate the SELECT statement on
|
||||||
|
** the right - the "B" select
|
||||||
|
*/
|
||||||
addrSelectB = sqlite3VdbeCurrentAddr(v);
|
addrSelectB = sqlite3VdbeCurrentAddr(v);
|
||||||
VdbeNoopComment((v, "Begin coroutine for right SELECT"));
|
VdbeNoopComment((v, "Begin coroutine for right SELECT"));
|
||||||
sqlite3SelectDestInit(&destB, SRT_Coroutine, 0);
|
savedLimit = p->iLimit;
|
||||||
sqlite3Select();
|
savedOffset = p->iOffset;
|
||||||
|
p->iLimit = regLimitB;
|
||||||
|
p->iOffset = 0;
|
||||||
|
sqlite3Select(pParse, p, &destB, 0, 0, 0, 0);
|
||||||
|
p->iLimit = savedLimit;
|
||||||
|
p->iOffset = savedOffset;
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
|
||||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB);
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||||
VdbeNoopComment((v, "End coroutine for right SELECT"));
|
VdbeNoopComment((v, "End coroutine for right SELECT"));
|
||||||
|
|
||||||
|
/* Generate a subroutine that outputs the current row of the A
|
||||||
|
** select as the next output row of the compound select and then
|
||||||
|
** advances the A select to its next row
|
||||||
|
*/
|
||||||
VdbeNoopComment((v, "Output routine for A"));
|
VdbeNoopComment((v, "Output routine for A"));
|
||||||
addrOutA = outputSubroutine(pParse, &destA, pDest);
|
addrOutA = outputSubroutine(pParse, p, &destA, pDest, regOutA, labelEnd);
|
||||||
|
|
||||||
|
/* Generate a subroutine that outputs the current row of the B
|
||||||
|
** select as the next output row of the compound select and then
|
||||||
|
** advances the B select to its next row
|
||||||
|
*/
|
||||||
VdbeNoopComment((v, "Output routine for B"));
|
VdbeNoopComment((v, "Output routine for B"));
|
||||||
addrOutB = outputSubroutine(pParse, &destB, pDest);
|
addrOutB = outputSubroutine(pParse, p, &destB, pDest, regOutB, labelEnd);
|
||||||
|
|
||||||
if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
/* Generate a subroutine to run when the results from select A
|
||||||
addrEofA = iEnd;
|
** are exhausted and only data in select B remains.
|
||||||
}else{
|
*/
|
||||||
VdbeNoopCommment((v, "eof-A subroutine"));
|
VdbeNoopComment((v, "eof-A subroutine"));
|
||||||
addrEofA = sqlite3VdbeCurrentAddr(v);
|
addrEofA = sqlite3VdbeCurrentAddr(v);
|
||||||
|
if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd);
|
||||||
|
}else{
|
||||||
if( op==TK_ALL ){
|
if( op==TK_ALL ){
|
||||||
j2 = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
j2 = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
||||||
}else{
|
}else{
|
||||||
assert( op==TK_UNION );
|
assert( op==TK_UNION );
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
sqlite3ExprCodeCopy(pParse, destB.iMem, destA.iMem, destB.nMem);
|
||||||
sqlite3ExprCodeMove(pParse, destB.iMem, destA.iMem, destB.nMem);
|
|
||||||
j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
||||||
sqlite3VdbeAddOp3(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem);
|
sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem,
|
||||||
sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+1, j2);
|
(char*)pKeyInfo, p4type);
|
||||||
|
p4type = P4_KEYINFO_STATIC;
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+4, j2);
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generate a subroutine to run when the results from select B
|
||||||
|
** are exhausted and only data in select A remains.
|
||||||
|
*/
|
||||||
if( op==TK_INTERSECT ){
|
if( op==TK_INTERSECT ){
|
||||||
addrEofA = iEnd;
|
addrEofB = addrEofA;
|
||||||
}else{
|
}else{
|
||||||
VdbeNoopCommment((v, "eof-B subroutine"));
|
VdbeNoopComment((v, "eof-B subroutine"));
|
||||||
addrEofA = sqlite3VdbeCurrentAddr(v);
|
addrEofB = sqlite3VdbeCurrentAddr(v);
|
||||||
if( op==TK_ALL || op==TK_EXCEPT ){
|
if( op==TK_ALL || op==TK_EXCEPT ){
|
||||||
j2 = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
j2 = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
||||||
}else{
|
}else{
|
||||||
assert( op==TK_UNION );
|
assert( op==TK_UNION );
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||||
sqlite3ExprCodeMove(pParse, destA.iMem, destB.iMem, destA.nMem);
|
sqlite3ExprCodeCopy(pParse, destA.iMem, destB.iMem, destA.nMem);
|
||||||
j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||||
sqlite3VdbeAddOp3(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem);
|
sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem,
|
||||||
sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+1, j2);
|
(char*)pKeyInfo, p4type);
|
||||||
|
p4type = P4_KEYINFO_STATIC;
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+4, j2);
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generate code to handle the case of A<B
|
||||||
|
*/
|
||||||
VdbeNoopComment((v, "A-lt-B subroutine"));
|
VdbeNoopComment((v, "A-lt-B subroutine"));
|
||||||
addrAltB = sqlite3VdbeCurrentAddr(v);
|
addrAltB = sqlite3VdbeCurrentAddr(v);
|
||||||
if( op!=TK_INTERSECT ){
|
if( op==TK_INTERSECT ){
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||||
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||||
}
|
}
|
||||||
addrAeqB = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||||
|
|
||||||
|
/* Generate code to handle the case of A==B
|
||||||
|
*/
|
||||||
if( op==TK_ALL ){
|
if( op==TK_ALL ){
|
||||||
addrAeqB = addrAltB;
|
addrAeqB = addrAltB;
|
||||||
}else if( op==TK_INTERSECT ){
|
}else{
|
||||||
VdbeNoopComment((v, "A-eq-B subroutine"));
|
VdbeNoopComment((v, "A-eq-B subroutine"));
|
||||||
|
addrAeqB = sqlite3VdbeCurrentAddr(v);
|
||||||
|
if( op==TK_INTERSECT ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||||
j2 = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
j2 = sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||||
sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.iMem,
|
sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.nMem,
|
||||||
pKeyInfo, P4_KEYINFO_STATIC);
|
(char*)pKeyInfo, p4type);
|
||||||
|
p4type = P4_KEYINFO_STATIC;
|
||||||
j3 = sqlite3VdbeCurrentAddr(v)+1;
|
j3 = sqlite3VdbeCurrentAddr(v)+1;
|
||||||
sqlite3VdbeAddOp3(v, OP_Jump, j3, j2, j3);
|
sqlite3VdbeAddOp3(v, OP_Jump, j3, j2, j3);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||||
|
}else{
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generate code to handle the case of A>B
|
||||||
|
*/
|
||||||
VdbeNoopComment((v, "A-gt-B subroutine"));
|
VdbeNoopComment((v, "A-gt-B subroutine"));
|
||||||
addrAgtB = sqlite3VdbeCurrentAddr(v);
|
addrAgtB = sqlite3VdbeCurrentAddr(v);
|
||||||
if( op==TK_ALL || op==TK_UNION ){
|
if( op==TK_ALL || op==TK_UNION ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||||
}
|
}else{
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||||
|
}
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCompare);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||||
|
|
||||||
|
/* This code runs once to initialize everything.
|
||||||
|
*/
|
||||||
sqlite3VdbeJumpHere(v, j1);
|
sqlite3VdbeJumpHere(v, j1);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, addrSelectA, regAddrA);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, addrSelectB, regAddrB);
|
sqlite3VdbeAddOp2(v, OP_Integer, addrSelectB, regAddrB);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA);
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||||
sqlite3VdbeResolve(v, labelCompare);
|
|
||||||
sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.iMem,
|
/* Implement the main merge loop
|
||||||
pKeyInfo, P4_KEYINFO_HANDOFF);
|
*/
|
||||||
|
sqlite3VdbeResolveLabel(v, labelCmpr);
|
||||||
|
sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.nMem,
|
||||||
|
(char*)pKeyInfo, p4type);
|
||||||
|
p4type = P4_KEYINFO_STATIC;
|
||||||
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
|
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
|
||||||
|
|
||||||
|
/* Jump to the this point in order to terminate the query.
|
||||||
|
*/
|
||||||
sqlite3VdbeResolveLabel(v, labelEnd);
|
sqlite3VdbeResolveLabel(v, labelEnd);
|
||||||
|
|
||||||
|
/* Set the number of output columns
|
||||||
|
*/
|
||||||
|
if( pDest->eDest==SRT_Callback ){
|
||||||
|
Select *pFirst = p;
|
||||||
|
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
||||||
|
generateColumnNames(pParse, 0, pFirst->pEList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the KeyInfo if unused.
|
||||||
|
*/
|
||||||
|
if( p4type==P4_KEYINFO_HANDOFF ){
|
||||||
|
sqlite3_free(pKeyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
||||||
|
**** subqueries ****/
|
||||||
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
#endif /***** ########### *****/
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIEW
|
#ifndef SQLITE_OMIT_VIEW
|
||||||
/* Forward Declarations */
|
/* Forward Declarations */
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.724 2008/06/23 14:03:45 danielk1977 Exp $
|
** @(#) $Id: sqliteInt.h,v 1.725 2008/06/24 00:32:36 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1161,7 +1161,7 @@ struct Expr {
|
|||||||
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
|
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
|
||||||
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
|
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
|
||||||
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
|
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
|
||||||
|
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
|
||||||
/*
|
/*
|
||||||
** These macros can be used to test, set, or clear bits in the
|
** These macros can be used to test, set, or clear bits in the
|
||||||
** Expr.flags field.
|
** Expr.flags field.
|
||||||
@@ -1449,10 +1449,8 @@ struct SelectDest {
|
|||||||
u8 eDest; /* How to dispose of the results */
|
u8 eDest; /* How to dispose of the results */
|
||||||
u8 affinity; /* Affinity used when eDest==SRT_Set */
|
u8 affinity; /* Affinity used when eDest==SRT_Set */
|
||||||
int iParm; /* A parameter used by the eDest disposal method */
|
int iParm; /* A parameter used by the eDest disposal method */
|
||||||
int regCoroutine; /* Program counter register for SRT_Coroutine */
|
|
||||||
int iMem; /* Base register where results are written */
|
int iMem; /* Base register where results are written */
|
||||||
int nMem; /* Number of registers allocated */
|
int nMem; /* Number of registers allocated */
|
||||||
int eofMem; /* Register holding EOF flag */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1913,6 +1911,7 @@ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
|
|||||||
void sqlite3WhereEnd(WhereInfo*);
|
void sqlite3WhereEnd(WhereInfo*);
|
||||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
||||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||||
|
void sqlite3ExprCodeCopy(Parse*, int, int, int);
|
||||||
void sqlite3ExprClearColumnCache(Parse*, int);
|
void sqlite3ExprClearColumnCache(Parse*, int);
|
||||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||||
int sqlite3ExprWritableRegister(Parse*,int,int);
|
int sqlite3ExprWritableRegister(Parse*,int,int);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the SELECT statement.
|
# focus of this file is testing the SELECT statement.
|
||||||
#
|
#
|
||||||
# $Id: select1.test,v 1.58 2008/06/23 18:49:45 danielk1977 Exp $
|
# $Id: select1.test,v 1.59 2008/06/24 00:32:36 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -544,6 +544,7 @@ do_test select1-6.21 {
|
|||||||
}
|
}
|
||||||
} {d}
|
} {d}
|
||||||
do_test select1-6.22 {
|
do_test select1-6.22 {
|
||||||
|
breakpoint
|
||||||
execsql {
|
execsql {
|
||||||
SELECT a FROM t6 WHERE b IN
|
SELECT a FROM t6 WHERE b IN
|
||||||
(SELECT b FROM t6 WHERE a<='b' UNION SELECT '3' AS x
|
(SELECT b FROM t6 WHERE a<='b' UNION SELECT '3' AS x
|
||||||
@@ -932,4 +933,3 @@ do_test select1-14.2 {
|
|||||||
} {0}
|
} {0}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user