mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-10 01:02:56 +03:00
Experimental code that tries to put the computation of subqueries inside a
subroutine, and reuse that subroutine if the same subquery is evaluated more than once. Current code does not work for CHECK constraints. FossilOrigin-Name: 6c44838adbe5dc482bc010e91a6dd7a0f777c989f443dd600740d2c783208e0d
This commit is contained in:
23
manifest
23
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Split\sthe\scode\sgeneration\sfor\sthe\sRHS\sof\sIN\soperators\sand\sfor\sSELECT\sand\nEXISTS\sexpressions\sinto\stwo\sseparate\ssubroutines,\sbecause\sthere\sis\snow\slittle\ncommonality\sbetween\sthose\sto\sfunctions.\sThis\sis\sintended\sto\shelp\smake\sthe\ncode\seasier\sto\sread\sand\smaintain.
|
C Experimental\scode\sthat\stries\sto\sput\sthe\scomputation\sof\ssubqueries\sinside\sa\nsubroutine,\sand\sreuse\sthat\ssubroutine\sif\sthe\ssame\ssubquery\sis\sevaluated\smore\nthan\sonce.\s\sCurrent\scode\sdoes\snot\swork\sfor\sCHECK\sconstraints.
|
||||||
D 2018-12-23T21:27:29.955
|
D 2018-12-24T02:34:49.752
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in d8b254f8bb81bab43c340d70d17dc3babab40fcc8a348c8255881f780a45fee6
|
F Makefile.in d8b254f8bb81bab43c340d70d17dc3babab40fcc8a348c8255881f780a45fee6
|
||||||
@@ -462,7 +462,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
|
|||||||
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
|
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
|
||||||
F src/dbstat.c 3c8bd4e77f0244fd2bd7cc90acf116ad2f8e82d70e536637f35ac2bc99b726f9
|
F src/dbstat.c 3c8bd4e77f0244fd2bd7cc90acf116ad2f8e82d70e536637f35ac2bc99b726f9
|
||||||
F src/delete.c f7938125847e8ef485448db5fbad29acb2991381a02887dd854c1617315ab9fb
|
F src/delete.c f7938125847e8ef485448db5fbad29acb2991381a02887dd854c1617315ab9fb
|
||||||
F src/expr.c 3f398a6698da6fccff353c09d5fc86e7e815386eeeaa9343360c6ef66167dcc6
|
F src/expr.c 98076b0c05b8ab467990c0a1b70377b70ad48c63e96f03b9d08d16b08798a892
|
||||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||||
F src/fkey.c 012dd7dba1a62fda6b76e633ab303b2232ee2874a685c915065227ab20ad6ae0
|
F src/fkey.c 012dd7dba1a62fda6b76e633ab303b2232ee2874a685c915065227ab20ad6ae0
|
||||||
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
|
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
|
||||||
@@ -515,7 +515,7 @@ F src/shell.c.in 207da30342db0b6fac8b2487abd60b059a5ea80cc9494bd1db76a1dd4aae7cc
|
|||||||
F src/sqlite.h.in b54cd42d2f3b739a00de540cafe2dcd0de3b8e1748a2db33a68def487e9e602f
|
F src/sqlite.h.in b54cd42d2f3b739a00de540cafe2dcd0de3b8e1748a2db33a68def487e9e602f
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
|
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
|
||||||
F src/sqliteInt.h 031e09cf6ea600e23fb4ce6e0a81f3f0e256b990dc6a71d21324d9ab8533b6cd
|
F src/sqliteInt.h 1b343307094ad33e5d38342df86e252fa997ef62f8521ca0a20f9997e2ed1081
|
||||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@@ -581,7 +581,7 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
|
|||||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||||
F src/vacuum.c 3ffe64ecfc94b7528c5d7bdb1c3a19d72fec63f2aa846e3b90f8de5dbbddf5aa
|
F src/vacuum.c 3ffe64ecfc94b7528c5d7bdb1c3a19d72fec63f2aa846e3b90f8de5dbbddf5aa
|
||||||
F src/vdbe.c 1f8e6c71c68631b5c4aaa82b84b262577bd29ca3a14871ed308785ee97ef919d
|
F src/vdbe.c 8d11da49bda1f504927df424923a415043f5825388e02722c4ac4c6eefc87a47
|
||||||
F src/vdbe.h 8990d668a89890a33326b0a29b992c4014b72f3b6cdcd9ee0e190593c247f9b0
|
F src/vdbe.h 8990d668a89890a33326b0a29b992c4014b72f3b6cdcd9ee0e190593c247f9b0
|
||||||
F src/vdbeInt.h 73f5051923f3f29779bfc374c0c68e23b8e5e3792def2e33e51b427edb890abd
|
F src/vdbeInt.h 73f5051923f3f29779bfc374c0c68e23b8e5e3792def2e33e51b427edb890abd
|
||||||
F src/vdbeapi.c 57a2d794a8833f269b878dbc24e955369bdb379af6c4e93ebc5ce1a20fa3daf4
|
F src/vdbeapi.c 57a2d794a8833f269b878dbc24e955369bdb379af6c4e93ebc5ce1a20fa3daf4
|
||||||
@@ -595,9 +595,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
|||||||
F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
|
F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
|
||||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
||||||
F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
|
F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
|
||||||
F src/where.c 3818e8a736a05d2cb194e64399af707e367fbcc5c251d785804d02eaf121288e
|
F src/where.c 05877beee56eeed88ea0bdb08a53236a63a2fee293ff3f57b1e679042d434bb4
|
||||||
F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
|
F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
|
||||||
F src/wherecode.c 1945ccec1bdcc783a4a1f810b26c33a0845d0ff44478094c82057bd03a527d39
|
F src/wherecode.c e819fc8ecbb4b30d790e8f1bcb6db9963e44514c5552e24f72e17a5d0822e9f7
|
||||||
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
|
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
|
||||||
F src/window.c ea81ecd031ed2cbc14b7db6fd7f4bee2471b894feae5fea0547b15b1e2dd8fb2
|
F src/window.c ea81ecd031ed2cbc14b7db6fd7f4bee2471b894feae5fea0547b15b1e2dd8fb2
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
@@ -1792,7 +1792,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 6231485114eb07b258cd0e6e163ca05f7e9cf5664e071808fcb1329b33e4c4f5
|
P 2b6494b1509f0d0189f98aa34c990eee99c775ff57826e79b2c5b0a12b4c97ad
|
||||||
R 2a6002750376d4a69fc079d42ab7e257
|
R fb44a7719019fd77dd18f789a3532b3a
|
||||||
|
T *branch * reuse-subqueries
|
||||||
|
T *sym-reuse-subqueries *
|
||||||
|
T -sym-trunk *
|
||||||
U drh
|
U drh
|
||||||
Z 5671bf9f2889b8158f9e3e76a5d3d072
|
Z dfb417c264f2e2790a098e45799008c5
|
||||||
|
@@ -1 +1 @@
|
|||||||
2b6494b1509f0d0189f98aa34c990eee99c775ff57826e79b2c5b0a12b4c97ad
|
6c44838adbe5dc482bc010e91a6dd7a0f777c989f443dd600740d2c783208e0d
|
127
src/expr.c
127
src/expr.c
@@ -2350,7 +2350,8 @@ int sqlite3FindInIndex(
|
|||||||
Expr *pX, /* The right-hand side (RHS) of the IN operator */
|
Expr *pX, /* The right-hand side (RHS) of the IN operator */
|
||||||
u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
|
u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
|
||||||
int *prRhsHasNull, /* Register holding NULL status. See notes */
|
int *prRhsHasNull, /* Register holding NULL status. See notes */
|
||||||
int *aiMap /* Mapping from Index fields to RHS fields */
|
int *aiMap, /* Mapping from Index fields to RHS fields */
|
||||||
|
int *piTab /* OUT: index to use */
|
||||||
){
|
){
|
||||||
Select *p; /* SELECT to the right of IN operator */
|
Select *p; /* SELECT to the right of IN operator */
|
||||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||||
@@ -2543,13 +2544,11 @@ int sqlite3FindInIndex(
|
|||||||
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
|
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
|
||||||
}
|
}
|
||||||
assert( pX->op==TK_IN );
|
assert( pX->op==TK_IN );
|
||||||
sqlite3CodeRhsOfIN(pParse, pX, eType==IN_INDEX_ROWID);
|
sqlite3CodeRhsOfIN(pParse, pX, iTab, eType==IN_INDEX_ROWID);
|
||||||
if( rMayHaveNull ){
|
if( rMayHaveNull ){
|
||||||
sqlite3SetHasNullFlag(v, pX->iTable, rMayHaveNull);
|
sqlite3SetHasNullFlag(v, iTab, rMayHaveNull);
|
||||||
}
|
}
|
||||||
pParse->nQueryLoop = savedNQueryLoop;
|
pParse->nQueryLoop = savedNQueryLoop;
|
||||||
}else{
|
|
||||||
pX->iTable = iTab;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
|
if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
|
||||||
@@ -2557,6 +2556,7 @@ int sqlite3FindInIndex(
|
|||||||
n = sqlite3ExprVectorSize(pX->pLeft);
|
n = sqlite3ExprVectorSize(pX->pLeft);
|
||||||
for(i=0; i<n; i++) aiMap[i] = i;
|
for(i=0; i<n; i++) aiMap[i] = i;
|
||||||
}
|
}
|
||||||
|
*piTab = iTab;
|
||||||
return eType;
|
return eType;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2639,7 +2639,11 @@ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
|
|||||||
** x IN (4,5,11) -- IN operator with list on right-hand side
|
** x IN (4,5,11) -- IN operator with list on right-hand side
|
||||||
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
|
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
|
||||||
**
|
**
|
||||||
** The pExpr parameter is the IN operator.
|
** The pExpr parameter is the IN operator. The cursor number for the
|
||||||
|
** constructed ephermeral table is returned. The first time the ephemeral
|
||||||
|
** table is computed, the cursor number is also stored in pExpr->iTable,
|
||||||
|
** however the cursor number returned might not be the same, as it might
|
||||||
|
** have been duplicated using OP_OpenDup.
|
||||||
**
|
**
|
||||||
** If parameter isRowid is non-zero, then LHS of the IN operator is guaranteed
|
** If parameter isRowid is non-zero, then LHS of the IN operator is guaranteed
|
||||||
** to be a non-null integer. In this case, the ephemeral table can be an
|
** to be a non-null integer. In this case, the ephemeral table can be an
|
||||||
@@ -2658,30 +2662,50 @@ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
|
|||||||
void sqlite3CodeRhsOfIN(
|
void sqlite3CodeRhsOfIN(
|
||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Expr *pExpr, /* The IN operator */
|
Expr *pExpr, /* The IN operator */
|
||||||
|
int iTab, /* Use this cursor number */
|
||||||
int isRowid /* If true, LHS is a rowid */
|
int isRowid /* If true, LHS is a rowid */
|
||||||
){
|
){
|
||||||
int jmpIfDynamic = -1; /* One-time test address */
|
int addrOnce = 0; /* Address of the OP_Once instruction at top */
|
||||||
int addr; /* Address of OP_OpenEphemeral instruction */
|
int addr; /* Address of OP_OpenEphemeral instruction */
|
||||||
Expr *pLeft; /* the LHS of the IN operator */
|
Expr *pLeft; /* the LHS of the IN operator */
|
||||||
KeyInfo *pKeyInfo = 0; /* Key information */
|
KeyInfo *pKeyInfo = 0; /* Key information */
|
||||||
int nVal; /* Size of vector pLeft */
|
int nVal; /* Size of vector pLeft */
|
||||||
Vdbe *v; /* The prepared statement under construction */
|
Vdbe *v; /* The prepared statement under construction */
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = pParse->pVdbe;
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
|
|
||||||
/* The evaluation of the RHS of IN operator must be repeated every time it
|
/* The evaluation of the IN must be repeated every time it
|
||||||
** is encountered if any of the following is true:
|
** is encountered if any of the following is true:
|
||||||
**
|
**
|
||||||
** * The right-hand side is a correlated subquery
|
** * The right-hand side is a correlated subquery
|
||||||
** * The right-hand side is an expression list containing variables
|
** * The right-hand side is an expression list containing variables
|
||||||
** * We are inside a trigger
|
** * We are inside a trigger
|
||||||
**
|
**
|
||||||
** If all of the above are false, then we can run this code just once
|
** If all of the above are false, then we can compute the RHS just once
|
||||||
** save the results, and reuse the same result on subsequent invocations.
|
** and reuse it many names.
|
||||||
*/
|
*/
|
||||||
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
||||||
jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
/* Reuse of the RHS is allowed */
|
||||||
|
/* If this routine has already been coded, but the previous code
|
||||||
|
** might not have been invoked yet, so invoke it now as a subroutine.
|
||||||
|
*/
|
||||||
|
if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
|
||||||
|
pExpr->y.sub.iAddr);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin coding the subroutine */
|
||||||
|
ExprSetProperty(pExpr, EP_Subrtn);
|
||||||
|
pExpr->y.sub.regReturn = ++pParse->nMem;
|
||||||
|
pExpr->y.sub.iAddr =
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
|
||||||
|
VdbeComment((v, "return address"));
|
||||||
|
|
||||||
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check to see if this is a vector IN operator */
|
/* Check to see if this is a vector IN operator */
|
||||||
@@ -2692,9 +2716,16 @@ void sqlite3CodeRhsOfIN(
|
|||||||
/* Construct the ephemeral table that will contain the content of
|
/* Construct the ephemeral table that will contain the content of
|
||||||
** RHS of the IN operator.
|
** RHS of the IN operator.
|
||||||
*/
|
*/
|
||||||
pExpr->iTable = pParse->nTab++;
|
pExpr->iTable = iTab;
|
||||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral,
|
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral,
|
||||||
pExpr->iTable, (isRowid?0:nVal));
|
pExpr->iTable, (isRowid?0:nVal));
|
||||||
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||||
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
|
VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId));
|
||||||
|
}else{
|
||||||
|
VdbeComment((v, "RHS of IN operator"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
|
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
|
||||||
|
|
||||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
@@ -2706,8 +2737,8 @@ void sqlite3CodeRhsOfIN(
|
|||||||
Select *pSelect = pExpr->x.pSelect;
|
Select *pSelect = pExpr->x.pSelect;
|
||||||
ExprList *pEList = pSelect->pEList;
|
ExprList *pEList = pSelect->pEList;
|
||||||
|
|
||||||
ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY",
|
ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d",
|
||||||
jmpIfDynamic>=0?"":"CORRELATED "
|
addrOnce?"":"CORRELATED ", pSelect->selId
|
||||||
));
|
));
|
||||||
assert( !isRowid );
|
assert( !isRowid );
|
||||||
/* If the LHS and RHS of the IN operator do not match, that
|
/* If the LHS and RHS of the IN operator do not match, that
|
||||||
@@ -2772,9 +2803,9 @@ void sqlite3CodeRhsOfIN(
|
|||||||
** this code only executes once. Because for a non-constant
|
** this code only executes once. Because for a non-constant
|
||||||
** expression we need to rerun this code each time.
|
** expression we need to rerun this code each time.
|
||||||
*/
|
*/
|
||||||
if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
|
if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
|
||||||
sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
|
sqlite3VdbeChangeToNoop(v, addrOnce);
|
||||||
jmpIfDynamic = -1;
|
addrOnce = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate the expression and insert it into the temp table */
|
/* Evaluate the expression and insert it into the temp table */
|
||||||
@@ -2799,8 +2830,11 @@ void sqlite3CodeRhsOfIN(
|
|||||||
if( pKeyInfo ){
|
if( pKeyInfo ){
|
||||||
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
|
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
|
||||||
}
|
}
|
||||||
if( jmpIfDynamic>=0 ){
|
if( addrOnce ){
|
||||||
sqlite3VdbeJumpHere(v, jmpIfDynamic);
|
sqlite3VdbeJumpHere(v, addrOnce);
|
||||||
|
/* Subroutine return */
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
||||||
|
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||||
@@ -2821,16 +2855,30 @@ void sqlite3CodeRhsOfIN(
|
|||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_SUBQUERY
|
#ifndef SQLITE_OMIT_SUBQUERY
|
||||||
int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||||
int jmpIfDynamic = -1; /* One-time test address */
|
int addrOnce = 0; /* Address of OP_Once at top of subroutine */
|
||||||
int rReg = 0; /* Register storing resulting */
|
int rReg = 0; /* Register storing resulting */
|
||||||
Select *pSel; /* SELECT statement to encode */
|
Select *pSel; /* SELECT statement to encode */
|
||||||
SelectDest dest; /* How to deal with SELECT result */
|
SelectDest dest; /* How to deal with SELECT result */
|
||||||
int nReg; /* Registers to allocate */
|
int nReg; /* Registers to allocate */
|
||||||
Expr *pLimit; /* New limit expression */
|
Expr *pLimit; /* New limit expression */
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
|
||||||
|
Vdbe *v = pParse->pVdbe;
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
|
|
||||||
/* The evaluation of the EXISTS/SELECT must be repeated every time it
|
/* If this routine has already been coded, then invoke it as a subroutine. */
|
||||||
|
if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr);
|
||||||
|
return pExpr->iTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin coding the subroutine */
|
||||||
|
ExprSetProperty(pExpr, EP_Subrtn);
|
||||||
|
pExpr->y.sub.regReturn = ++pParse->nMem;
|
||||||
|
pExpr->y.sub.iAddr =
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
|
||||||
|
VdbeComment((v, "return address"));
|
||||||
|
|
||||||
|
/* The evaluation of the IN/EXISTS/SELECT must be repeated every time it
|
||||||
** is encountered if any of the following is true:
|
** is encountered if any of the following is true:
|
||||||
**
|
**
|
||||||
** * The right-hand side is a correlated subquery
|
** * The right-hand side is a correlated subquery
|
||||||
@@ -2841,7 +2889,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|||||||
** save the results, and reuse the same result on subsequent invocations.
|
** save the results, and reuse the same result on subsequent invocations.
|
||||||
*/
|
*/
|
||||||
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
||||||
jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For a SELECT, generate code to put the values for all columns of
|
/* For a SELECT, generate code to put the values for all columns of
|
||||||
@@ -2861,7 +2909,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|||||||
|
|
||||||
pSel = pExpr->x.pSelect;
|
pSel = pExpr->x.pSelect;
|
||||||
ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY",
|
ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY",
|
||||||
jmpIfDynamic>=0?"":"CORRELATED "));
|
addrOnce?"":"CORRELATED "));
|
||||||
nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
|
nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
|
||||||
sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
|
sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
|
||||||
pParse->nMem += nReg;
|
pParse->nMem += nReg;
|
||||||
@@ -2887,13 +2935,16 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|||||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
rReg = dest.iSDParm;
|
pExpr->iTable = rReg = dest.iSDParm;
|
||||||
ExprSetVVAProperty(pExpr, EP_NoReduce);
|
ExprSetVVAProperty(pExpr, EP_NoReduce);
|
||||||
|
if( addrOnce ){
|
||||||
if( jmpIfDynamic>=0 ){
|
sqlite3VdbeJumpHere(v, addrOnce);
|
||||||
sqlite3VdbeJumpHere(v, jmpIfDynamic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subroutine return */
|
||||||
|
sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
||||||
|
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||||
|
|
||||||
return rReg;
|
return rReg;
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||||
@@ -2968,6 +3019,7 @@ static void sqlite3ExprCodeIN(
|
|||||||
int addrTruthOp; /* Address of opcode that determines the IN is true */
|
int addrTruthOp; /* Address of opcode that determines the IN is true */
|
||||||
int destNotNull; /* Jump here if a comparison is not true in step 6 */
|
int destNotNull; /* Jump here if a comparison is not true in step 6 */
|
||||||
int addrTop; /* Top of the step-6 loop */
|
int addrTop; /* Top of the step-6 loop */
|
||||||
|
int iTab = 0; /* Index to use */
|
||||||
|
|
||||||
pLeft = pExpr->pLeft;
|
pLeft = pExpr->pLeft;
|
||||||
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
|
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
|
||||||
@@ -2979,7 +3031,7 @@ static void sqlite3ExprCodeIN(
|
|||||||
if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
|
if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
|
||||||
|
|
||||||
/* Attempt to compute the RHS. After this step, if anything other than
|
/* Attempt to compute the RHS. After this step, if anything other than
|
||||||
** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable
|
** IN_INDEX_NOOP is returned, the table opened with cursor iTab
|
||||||
** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
|
** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
|
||||||
** the RHS has not yet been coded. */
|
** the RHS has not yet been coded. */
|
||||||
v = pParse->pVdbe;
|
v = pParse->pVdbe;
|
||||||
@@ -2987,7 +3039,8 @@ static void sqlite3ExprCodeIN(
|
|||||||
VdbeNoopComment((v, "begin IN expr"));
|
VdbeNoopComment((v, "begin IN expr"));
|
||||||
eType = sqlite3FindInIndex(pParse, pExpr,
|
eType = sqlite3FindInIndex(pParse, pExpr,
|
||||||
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
|
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
|
||||||
destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
|
destIfFalse==destIfNull ? 0 : &rRhsHasNull,
|
||||||
|
aiMap, &iTab);
|
||||||
|
|
||||||
assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
|
assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
|
||||||
|| eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
|
|| eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
|
||||||
@@ -3095,19 +3148,19 @@ static void sqlite3ExprCodeIN(
|
|||||||
/* In this case, the RHS is the ROWID of table b-tree and so we also
|
/* In this case, the RHS is the ROWID of table b-tree and so we also
|
||||||
** know that the RHS is non-NULL. Hence, we combine steps 3 and 4
|
** know that the RHS is non-NULL. Hence, we combine steps 3 and 4
|
||||||
** into a single opcode. */
|
** into a single opcode. */
|
||||||
sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs);
|
sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */
|
addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
|
sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
|
||||||
if( destIfFalse==destIfNull ){
|
if( destIfFalse==destIfNull ){
|
||||||
/* Combine Step 3 and Step 5 into a single opcode */
|
/* Combine Step 3 and Step 5 into a single opcode */
|
||||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse,
|
sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse,
|
||||||
rLhs, nVector); VdbeCoverage(v);
|
rLhs, nVector); VdbeCoverage(v);
|
||||||
goto sqlite3ExprCodeIN_finished;
|
goto sqlite3ExprCodeIN_finished;
|
||||||
}
|
}
|
||||||
/* Ordinary Step 3, for the case where FALSE and NULL are distinct */
|
/* Ordinary Step 3, for the case where FALSE and NULL are distinct */
|
||||||
addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0,
|
addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0,
|
||||||
rLhs, nVector); VdbeCoverage(v);
|
rLhs, nVector); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3132,7 +3185,7 @@ static void sqlite3ExprCodeIN(
|
|||||||
** of the RHS.
|
** of the RHS.
|
||||||
*/
|
*/
|
||||||
if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
|
if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
|
||||||
addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
|
addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
if( nVector>1 ){
|
if( nVector>1 ){
|
||||||
destNotNull = sqlite3VdbeMakeLabel(v);
|
destNotNull = sqlite3VdbeMakeLabel(v);
|
||||||
@@ -3147,7 +3200,7 @@ static void sqlite3ExprCodeIN(
|
|||||||
int r3 = sqlite3GetTempReg(pParse);
|
int r3 = sqlite3GetTempReg(pParse);
|
||||||
p = sqlite3VectorFieldSubexpr(pLeft, i);
|
p = sqlite3VectorFieldSubexpr(pLeft, i);
|
||||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3);
|
sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3);
|
||||||
sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
|
sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
|
||||||
(void*)pColl, P4_COLLSEQ);
|
(void*)pColl, P4_COLLSEQ);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
@@ -3156,7 +3209,7 @@ static void sqlite3ExprCodeIN(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||||
if( nVector>1 ){
|
if( nVector>1 ){
|
||||||
sqlite3VdbeResolveLabel(v, destNotNull);
|
sqlite3VdbeResolveLabel(v, destNotNull);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1);
|
sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
|
|
||||||
/* Step 7: If we reach this point, we know that the result must
|
/* Step 7: If we reach this point, we know that the result must
|
||||||
|
@@ -2485,6 +2485,10 @@ struct Expr {
|
|||||||
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
||||||
** for a column of an index on an expression */
|
** for a column of an index on an expression */
|
||||||
Window *pWin; /* TK_FUNCTION: Window definition for the func */
|
Window *pWin; /* TK_FUNCTION: Window definition for the func */
|
||||||
|
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
|
||||||
|
int iAddr; /* Subroutine entry address */
|
||||||
|
int regReturn; /* Register used to hold return address */
|
||||||
|
} sub;
|
||||||
} y;
|
} y;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2516,6 +2520,7 @@ struct Expr {
|
|||||||
#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
||||||
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
||||||
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
||||||
|
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The EP_Propagate mask is a set of properties that automatically propagate
|
** The EP_Propagate mask is a set of properties that automatically propagate
|
||||||
@@ -4258,7 +4263,7 @@ void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
|
|||||||
int sqlite3GetToken(const unsigned char *, int *);
|
int sqlite3GetToken(const unsigned char *, int *);
|
||||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||||
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||||
void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
|
void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int);
|
||||||
int sqlite3CodeSubselect(Parse*, Expr*);
|
int sqlite3CodeSubselect(Parse*, Expr*);
|
||||||
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
||||||
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
|
void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
|
||||||
@@ -4511,7 +4516,7 @@ const char *sqlite3JournalModename(int);
|
|||||||
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
|
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
|
||||||
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
|
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
|
||||||
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
|
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
|
||||||
int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
|
int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*);
|
||||||
|
|
||||||
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
||||||
int sqlite3JournalSize(sqlite3_vfs *);
|
int sqlite3JournalSize(sqlite3_vfs *);
|
||||||
|
@@ -3610,7 +3610,8 @@ case OP_OpenDup: {
|
|||||||
pCx->isEphemeral = 1;
|
pCx->isEphemeral = 1;
|
||||||
pCx->pKeyInfo = pOrig->pKeyInfo;
|
pCx->pKeyInfo = pOrig->pKeyInfo;
|
||||||
pCx->isTable = pOrig->isTable;
|
pCx->isTable = pOrig->isTable;
|
||||||
rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
pCx->pgnoRoot = pOrig->pgnoRoot;
|
||||||
|
rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
|
||||||
pCx->pKeyInfo, pCx->uc.pCursor);
|
pCx->pKeyInfo, pCx->uc.pCursor);
|
||||||
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
|
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
|
||||||
** opened for a database. Since there is already an open cursor when this
|
** opened for a database. Since there is already an open cursor when this
|
||||||
@@ -3682,6 +3683,7 @@ case OP_OpenEphemeral: {
|
|||||||
assert( pgno==MASTER_ROOT+1 );
|
assert( pgno==MASTER_ROOT+1 );
|
||||||
assert( pKeyInfo->db==db );
|
assert( pKeyInfo->db==db );
|
||||||
assert( pKeyInfo->enc==ENC(db) );
|
assert( pKeyInfo->enc==ENC(db) );
|
||||||
|
pCx->pgnoRoot = pgno;
|
||||||
rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR,
|
rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR,
|
||||||
pKeyInfo, pCx->uc.pCursor);
|
pKeyInfo, pCx->uc.pCursor);
|
||||||
}
|
}
|
||||||
@@ -3690,6 +3692,7 @@ case OP_OpenEphemeral: {
|
|||||||
rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
||||||
0, pCx->uc.pCursor);
|
0, pCx->uc.pCursor);
|
||||||
pCx->isTable = 1;
|
pCx->isTable = 1;
|
||||||
|
pCx->pgnoRoot = MASTER_ROOT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( rc ) goto abort_due_to_error;
|
if( rc ) goto abort_due_to_error;
|
||||||
|
@@ -854,6 +854,7 @@ static void constructAutomaticIndex(
|
|||||||
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
|
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
|
||||||
pTabItem->regResult, 1);
|
pTabItem->regResult, 1);
|
||||||
sqlite3VdbeGoto(v, addrTop);
|
sqlite3VdbeGoto(v, addrTop);
|
||||||
|
pTabItem->fg.viaCoroutine = 0;
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
|
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
|
@@ -538,16 +538,17 @@ static int codeEqualityTerm(
|
|||||||
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
|
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iTab = 0;
|
||||||
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
|
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
|
||||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
|
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
|
||||||
}else{
|
}else{
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
||||||
|
|
||||||
if( !db->mallocFailed ){
|
if( !db->mallocFailed ){
|
||||||
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
||||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
|
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
||||||
pTerm->pExpr->iTable = pX->iTable;
|
pTerm->pExpr->iTable = iTab;
|
||||||
}
|
}
|
||||||
sqlite3ExprDelete(db, pX);
|
sqlite3ExprDelete(db, pX);
|
||||||
pX = pTerm->pExpr;
|
pX = pTerm->pExpr;
|
||||||
@@ -557,7 +558,6 @@ static int codeEqualityTerm(
|
|||||||
testcase( bRev );
|
testcase( bRev );
|
||||||
bRev = !bRev;
|
bRev = !bRev;
|
||||||
}
|
}
|
||||||
iTab = pX->iTable;
|
|
||||||
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
|
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
|
||||||
VdbeCoverageIf(v, bRev);
|
VdbeCoverageIf(v, bRev);
|
||||||
VdbeCoverageIf(v, !bRev);
|
VdbeCoverageIf(v, !bRev);
|
||||||
@@ -2197,7 +2197,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
|||||||
if( pAlt->wtFlags & (TERM_CODED) ) continue;
|
if( pAlt->wtFlags & (TERM_CODED) ) continue;
|
||||||
if( (pAlt->eOperator & WO_IN)
|
if( (pAlt->eOperator & WO_IN)
|
||||||
&& (pAlt->pExpr->flags & EP_xIsSelect)
|
&& (pAlt->pExpr->flags & EP_xIsSelect)
|
||||||
&& (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
|
// && (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
|
||||||
){
|
){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user