1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

Fix where.c handling of "IN (SELECT ...)" expressions when the SELECT returns more than one result column. Also error handling for other row value constructor cases.

FossilOrigin-Name: 061b8006034f06a0311b4304c8b14d2c8b0153df
This commit is contained in:
dan
2016-07-26 18:06:08 +00:00
parent ba00e30a3a
commit 8da209b169
14 changed files with 233 additions and 70 deletions

View File

@ -1,5 +1,5 @@
C Allow\svector\sIN(SELECT\s...)\sexpressions\sto\suse\san\sindex\sif\seither\sall\sthe\sindexed\scolumns\sare\sdeclared\sNOT\sNULL\sor\sif\sthere\sis\sno\sdifference\sbetween\sthe\sexpression\sevaluating\sto\s0\sand\sNULL\s(as\sin\sa\sWHERE\sclause). C Fix\swhere.c\shandling\sof\s"IN\s(SELECT\s...)"\sexpressions\swhen\sthe\sSELECT\sreturns\smore\sthan\sone\sresult\scolumn.\sAlso\serror\shandling\sfor\sother\srow\svalue\sconstructor\scases.
D 2016-07-23T20:24:06.382 D 2016-07-26T18:06:08.100
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
@ -337,7 +337,7 @@ F src/ctime.c 61949e83c4c36e37195a8398ebc752780b534d95
F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39 F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0 F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
F src/expr.c 8ff9d70cc2077020327d1fa551558bb03e267da4 F src/expr.c f84861eaaf557df45bb8f4513a78a05fbb0ad368
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413 F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045 F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
@ -381,7 +381,7 @@ F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
F src/prepare.c 22df6171aec1d86904ed2ad30c2348a5748aa04e F src/prepare.c 22df6171aec1d86904ed2ad30c2348a5748aa04e
F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1 F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 9680caadd54772699e5a0a8ebd680e014703e4ee F src/resolve.c 5c4d301a855d0245ddcc27365ddcbddd2f244665
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 0115f5d222f5cf9b5511ec4072088417354d738a F src/select.c 0115f5d222f5cf9b5511ec4072088417354d738a
F src/shell.c a8a9e392a6a2777fabf5feb536931cb190f235e5 F src/shell.c a8a9e392a6a2777fabf5feb536931cb190f235e5
@ -463,10 +463,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a
F src/wal.h 6dd221ed384afdc204bc61e25c23ef7fd5a511f2 F src/wal.h 6dd221ed384afdc204bc61e25c23ef7fd5a511f2
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
F src/where.c 898a45969bae1298cbaaaf05e6aeacfb45971293 F src/where.c e7054b2c1fe31fef5136e5735d7958f5c2c7707d
F src/whereInt.h 1ad3be2a43cb821418e1100476a3a14cd57635c4 F src/whereInt.h 14dd243e13b81cbb0a66063d38b70f93a7d6e613
F src/wherecode.c eb0f5e8700afb110cb96fb873c0e9a015a9f63ff F src/wherecode.c 03fbaa63909d7e4b8af986595b811ae591032240
F src/whereexpr.c d88ee6ce356cb9fd986d0e81249a2cd66a513093 F src/whereexpr.c b896f8ff6a53cbd3daaee84ec33e39098762bb46
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@ -643,7 +643,7 @@ F test/e_createtable.test d4c6059d44dcd4b636de9aae322766062b471844
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412 F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306 F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
F test/e_expr.test 03a84a6fa9bd3472112d6bd4599f5269f5f74803 F test/e_expr.test 3f9e639b5df18de36c0aa700703589cd65281174
F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707 F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
F test/e_insert.test 3de217e95094d3d165992a6de1164bbc4bd92dc7 F test/e_insert.test 3de217e95094d3d165992a6de1164bbc4bd92dc7
@ -822,7 +822,7 @@ F test/hook.test 3b7b99d0eece6d279812c2aef6fa08bdfabc633e
F test/icu.test 73956798bace8982909c00476b216714a6d0559a F test/icu.test 73956798bace8982909c00476b216714a6d0559a
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607 F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test 61a24ae38d4b64ec69f06ccdf022992f68a98176 F test/in.test 41d18d4bcd27c55d0bc6b6ddc8ff9e85e91728a4
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
@ -1019,7 +1019,7 @@ F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test 5b7509f384f4f6fae1af3c8c104c8ca299fea18d F test/rowid.test 5b7509f384f4f6fae1af3c8c104c8ca299fea18d
F test/rowvalue.test 979738b3d49f1d93e3fee56a71d4446217917abc F test/rowvalue.test 979738b3d49f1d93e3fee56a71d4446217917abc
F test/rowvalue2.test 8d5dfe75b8f4d1868a2f91f0356f20d36cba64ff F test/rowvalue2.test 8d5dfe75b8f4d1868a2f91f0356f20d36cba64ff
F test/rowvalue3.test 72a9fe5ad30df2d422876466e180c148ab88dc42 F test/rowvalue3.test eeec47b4de27217a012dd142956b01af4e9bd6f2
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d
@ -1043,7 +1043,7 @@ F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328 F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0 F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
F test/select7.test 95e370c42d47c3c52377d05e9ffc01ccff7c1f61 F test/select7.test f659f231489349e8c5734e610803d7654207318f
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
F test/selectA.test 101e722370ac6e84978c2958b8931c78b10a1709 F test/selectA.test 101e722370ac6e84978c2958b8931c78b10a1709
@ -1111,7 +1111,7 @@ F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/subselect.test ccec43f85d488c6c4b6f98ea2dfa95b6086871c0
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8 F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12 F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
@ -1131,7 +1131,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
F test/tester.tcl a52b5be1bb586afa1c8bcdcd4b86588645e1ae52 F test/tester.tcl e1379282de5810a047c75d84eb6c914e00743b7e
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@ -1509,7 +1509,7 @@ 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 60fed5cdd4a44aefa1b4d505adeb7936f2f0b952 P e2fd6f49b1b145bec09c581cc982b89429643ae9
R 1dc4c60c16780168f167fe34d6f77ee9 R a369e1eed01f702cd78474a2d1d557f1
U dan U dan
Z f82474a4f9b8fbec7649c9e9d834d395 Z 9143269c80fa998d2598183a7a999846

View File

@ -1 +1 @@
e2fd6f49b1b145bec09c581cc982b89429643ae9 061b8006034f06a0311b4304c8b14d2c8b0153df

View File

@ -339,6 +339,19 @@ static Expr *exprVectorField(Expr *pVector, int i){
return pVector->x.pList->a[i].pExpr; return pVector->x.pList->a[i].pExpr;
} }
static int exprVectorSubselect(Parse *pParse, Expr *pExpr){
int reg = 0;
if( pExpr->flags & EP_xIsSelect ){
assert( pExpr->op==TK_REGISTER || pExpr->op==TK_SELECT );
if( pExpr->op==TK_REGISTER ){
reg = pExpr->iTable;
}else{
reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
}
}
return reg;
}
static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){ static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
Expr *pLeft = pExpr->pLeft; Expr *pLeft = pExpr->pLeft;
@ -389,16 +402,8 @@ static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){
break; break;
} }
if( pLeft->flags & EP_xIsSelect ){ regLeft = exprVectorSubselect(pParse, pLeft);
assert( pLeft->op==TK_SELECT || pLeft->op==TK_REGISTER ); regRight = exprVectorSubselect(pParse, pRight);
regLeft = sqlite3ExprCodeTarget(pParse, pLeft, 1);
assert( regLeft!=1 );
}
if( pRight->flags & EP_xIsSelect ){
assert( pRight->op==TK_SELECT || pRight->op==TK_REGISTER );
regRight = sqlite3ExprCodeTarget(pParse, pRight, 1);
assert( regRight!=1 );
}
if( pParse->nErr ) return; if( pParse->nErr ) return;
for(i=0; i<nLeft; i++){ for(i=0; i<nLeft; i++){
@ -2064,7 +2069,7 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
for(i=0; i<nVal; i++){ for(i=0; i<nVal; i++){
Expr *pA; Expr *pA;
char a; char a;
if( nVal==1 ){ if( nVal==1 && 0 ){
pA = pLeft; pA = pLeft;
}else{ }else{
pA = exprVectorField(pLeft, i); pA = exprVectorField(pLeft, i);
@ -2077,6 +2082,19 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
return zRet; return zRet;
} }
#ifndef SQLITE_OMIT_SUBQUERY
/*
** Load the Parse object passed as the first argument with an error
** message of the form:
**
** "sub-select returns N columns - expected M"
*/
void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
const char *zFmt = "sub-select returns %d columns - expected %d";
sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
}
#endif
/* /*
** Generate code for scalar subqueries used as a subquery expression, EXISTS, ** Generate code for scalar subqueries used as a subquery expression, EXISTS,
** or IN operators. Examples: ** or IN operators. Examples:
@ -2180,8 +2198,7 @@ int sqlite3CodeSubselect(
assert( !isRowid ); assert( !isRowid );
if( pEList->nExpr!=nVal ){ if( pEList->nExpr!=nVal ){
sqlite3ErrorMsg(pParse, "SELECT has %d columns - expected %d", sqlite3SubselectError(pParse, pEList->nExpr, nVal);
pEList->nExpr, nVal);
}else{ }else{
SelectDest dest; SelectDest dest;
int i; int i;
@ -3350,9 +3367,14 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: case TK_EXISTS:
case TK_SELECT: { case TK_SELECT: {
int nCol;
testcase( op==TK_EXISTS ); testcase( op==TK_EXISTS );
testcase( op==TK_SELECT ); testcase( op==TK_SELECT );
inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
sqlite3SubselectError(pParse, nCol, 1);
}else{
inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
}
break; break;
} }
case TK_IN: { case TK_IN: {

View File

@ -767,7 +767,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
} }
if( pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1 ){ if( pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1 ){
if( !ExprHasProperty(pExpr, EP_VectorOk) ){ if( !ExprHasProperty(pExpr, EP_VectorOk) && 0 ){
sqlite3ErrorMsg(pParse, "invalid use of row value"); sqlite3ErrorMsg(pParse, "invalid use of row value");
}else{ }else{
ExprSetProperty(pExpr, EP_Vector); ExprSetProperty(pExpr, EP_Vector);

View File

@ -4713,10 +4713,12 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeResolveLabel(v, pLevel->addrNxt); sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
sqlite3VdbeJumpHere(v, pIn->addrInTop+1); sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); if( pIn->eEndLoopOp!=OP_Noop ){
VdbeCoverage(v); sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); VdbeCoverage(v);
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
}
sqlite3VdbeJumpHere(v, pIn->addrInTop-1); sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
} }
} }

View File

@ -248,6 +248,7 @@ struct WhereTerm {
Expr *pExpr; /* Pointer to the subexpression that is this term */ Expr *pExpr; /* Pointer to the subexpression that is this term */
int iParent; /* Disable pWC->a[iParent] when this term disabled */ int iParent; /* Disable pWC->a[iParent] when this term disabled */
int leftCursor; /* Cursor number of X in "X <op> <expr>" */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */
int iField; /* Field in (?,?,?) IN (SELECT...) vector */
union { union {
int leftColumn; /* Column number of X in "X <op> <expr>" */ int leftColumn; /* Column number of X in "X <op> <expr>" */
WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */

View File

@ -356,6 +356,7 @@ static int codeEqualityTerm(
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int iReg; /* Register holding results */ int iReg; /* Register holding results */
assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
assert( iTarget>0 ); assert( iTarget>0 );
if( pX->op==TK_EQ || pX->op==TK_IS ){ if( pX->op==TK_EQ || pX->op==TK_IS ){
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
@ -368,6 +369,9 @@ static int codeEqualityTerm(
int iTab; int iTab;
struct InLoop *pIn; struct InLoop *pIn;
WhereLoop *pLoop = pLevel->pWLoop; WhereLoop *pLoop = pLevel->pWLoop;
int i;
int nEq = 0;
int *aiMap = 0;
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
&& pLoop->u.btree.pIndex!=0 && pLoop->u.btree.pIndex!=0
@ -379,7 +383,52 @@ static int codeEqualityTerm(
} }
assert( pX->op==TK_IN ); assert( pX->op==TK_IN );
iReg = iTarget; iReg = iTarget;
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
for(i=0; i<iEq; i++){
if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
disableTerm(pLevel, pTerm);
return iTarget;
}
}
for(i=iEq;i<pLoop->nLTerm; i++){
if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ) nEq++;
}
if( nEq>1 ){
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq);
if( !aiMap ) return 0;
}
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
}else{
sqlite3 *db = pParse->db;
ExprList *pOrigRhs = pX->x.pSelect->pEList;
ExprList *pOrigLhs = pX->pLeft->x.pList;
ExprList *pRhs = 0; /* New Select.pEList for RHS */
ExprList *pLhs = 0; /* New pX->pLeft vector */
for(i=iEq;i<pLoop->nLTerm; i++){
if( pLoop->aLTerm[i]->pExpr==pX ){
int iField = pLoop->aLTerm[i]->iField - 1;
Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0);
Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0);
pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs);
pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs);
}
}
pX->x.pSelect->pEList = pRhs;
pX->pLeft->x.pList = pLhs;
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
pX->x.pSelect->pEList = pOrigRhs;
pX->pLeft->x.pList = pOrigLhs;
sqlite3ExprListDelete(pParse->db, pLhs);
sqlite3ExprListDelete(pParse->db, pRhs);
}
if( eType==IN_INDEX_INDEX_DESC ){ if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev ); testcase( bRev );
bRev = !bRev; bRev = !bRev;
@ -389,28 +438,44 @@ static int codeEqualityTerm(
VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev); VdbeCoverageIf(v, !bRev);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
pLoop->wsFlags |= WHERE_IN_ABLE; pLoop->wsFlags |= WHERE_IN_ABLE;
if( pLevel->u.in.nIn==0 ){ if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(v); pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
} }
pLevel->u.in.nIn++;
i = pLevel->u.in.nIn;
pLevel->u.in.nIn += nEq;
pLevel->u.in.aInLoop = pLevel->u.in.aInLoop =
sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
pIn = pLevel->u.in.aInLoop; pIn = pLevel->u.in.aInLoop;
if( pIn ){ if( pIn ){
pIn += pLevel->u.in.nIn - 1; int iMap = 0; /* Index in aiMap[] */
pIn->iCur = iTab; pIn += i;
if( eType==IN_INDEX_ROWID ){ for(i=iEq;i<pLoop->nLTerm; i++, pIn++){
pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); if( pLoop->aLTerm[i]->pExpr==pX ){
}else{ if( eType==IN_INDEX_ROWID ){
pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); assert( nEq==1 && i==iEq );
pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
}else{
int iCol = aiMap ? aiMap[iMap++] : 0;
int iOut = iReg + i - iEq;
pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
}
if( i==iEq ){
pIn->iCur = iTab;
pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
}else{
pIn->eEndLoopOp = OP_Noop;
}
}
sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
} }
pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
}else{ }else{
pLevel->u.in.nIn = 0; pLevel->u.in.nIn = 0;
} }
sqlite3DbFree(pParse->db, aiMap);
#endif #endif
} }
disableTerm(pLevel, pTerm); disableTerm(pLevel, pTerm);

View File

@ -960,6 +960,12 @@ static void exprAnalyze(
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
if( op==TK_IN && pTerm->iField>0 ){
assert( pLeft->op==TK_VECTOR );
pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
}
if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){ if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
pTerm->leftCursor = iCur; pTerm->leftCursor = iCur;
pTerm->u.leftColumn = iColumn; pTerm->u.leftColumn = iColumn;
@ -1195,6 +1201,19 @@ static void exprAnalyze(
} }
} }
if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
&& pExpr->pLeft->op==TK_VECTOR
){
int i;
for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
int idxNew;
idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
pWC->a[idxNew].iField = i+1;
exprAnalyze(pSrc, pWC, idxNew);
markTermAsChild(pWC, idxNew, idxTerm);
}
}
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/* When sqlite_stat3 histogram data is available an operator of the /* When sqlite_stat3 histogram data is available an operator of the
** form "x IS NOT NULL" can sometimes be evaluated more efficiently ** form "x IS NOT NULL" can sometimes be evaluated more efficiently

View File

@ -1809,7 +1809,7 @@ do_expr_test e_expr-35.1.6 {
# The following block tests that errors are returned in a bunch of cases # The following block tests that errors are returned in a bunch of cases
# where a subquery returns more than one column. # where a subquery returns more than one column.
# #
set M {only a single result allowed for a SELECT that is part of an expression} set M {/1 {sub-select returns [23] columns - expected 1}/}
foreach {tn sql} { foreach {tn sql} {
1 { SELECT (SELECT * FROM t2 UNION SELECT a+1, b+1 FROM t2) } 1 { SELECT (SELECT * FROM t2 UNION SELECT a+1, b+1 FROM t2) }
2 { SELECT (SELECT * FROM t2 UNION SELECT a+1, b+1 FROM t2 ORDER BY 1) } 2 { SELECT (SELECT * FROM t2 UNION SELECT a+1, b+1 FROM t2 ORDER BY 1) }
@ -1818,7 +1818,7 @@ foreach {tn sql} {
5 { SELECT (SELECT * FROM t2) } 5 { SELECT (SELECT * FROM t2) }
6 { SELECT (SELECT * FROM (SELECT 1, 2, 3)) } 6 { SELECT (SELECT * FROM (SELECT 1, 2, 3)) }
} { } {
do_catchsql_test e_expr-35.2.$tn $sql [list 1 $M] do_catchsql_test e_expr-35.2.$tn $sql $M
} }
# EVIDENCE-OF: R-35764-28041 The result of the expression is the value # EVIDENCE-OF: R-35764-28041 The result of the expression is the value

View File

@ -314,7 +314,7 @@ do_test in-9.4 {
catchsql { catchsql {
SELECT b FROM t1 WHERE a NOT IN tb; SELECT b FROM t1 WHERE a NOT IN tb;
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
# IN clauses in CHECK constraints. Ticket #1645 # IN clauses in CHECK constraints. Ticket #1645
# #
@ -391,28 +391,28 @@ do_test in-12.2 {
SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2 SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2
); );
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
do_test in-12.3 { do_test in-12.3 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
SELECT a, b FROM t3 UNION SELECT a, b FROM t2 SELECT a, b FROM t3 UNION SELECT a, b FROM t2
); );
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
do_test in-12.4 { do_test in-12.4 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
SELECT a, b FROM t3 EXCEPT SELECT a, b FROM t2 SELECT a, b FROM t3 EXCEPT SELECT a, b FROM t2
); );
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
do_test in-12.5 { do_test in-12.5 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
SELECT a, b FROM t3 INTERSECT SELECT a, b FROM t2 SELECT a, b FROM t3 INTERSECT SELECT a, b FROM t2
); );
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
do_test in-12.6 { do_test in-12.6 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
@ -478,7 +478,7 @@ do_test in-12.14 {
SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2 SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2
); );
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
do_test in-12.15 { do_test in-12.15 {
catchsql { catchsql {
SELECT * FROM t2 WHERE a IN ( SELECT * FROM t2 WHERE a IN (
@ -629,11 +629,12 @@ do_test in-13.14 {
} }
} {} } {}
breakpoint
do_test in-13.15 { do_test in-13.15 {
catchsql { catchsql {
SELECT 0 WHERE (SELECT 0,0) OR (0 IN (1,2)); SELECT 0 WHERE (SELECT 0,0) OR (0 IN (1,2));
} }
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
do_test in-13.X { do_test in-13.X {

View File

@ -42,11 +42,56 @@ foreach {tn sql res} {
do_execsql_test 1.$tn $sql $res do_execsql_test 1.$tn $sql $res
} }
#explain_i { SELECT (4, NULL) IN (SELECT a, b FROM t1) } #-------------------------------------------------------------------------
#do_execsql_test 2 { SELECT (4, NULL) IN (SELECT a, b FROM t1) } {}
do_execsql_test 2.0 {
CREATE TABLE z1(x, y, z);
CREATE TABLE kk(a, b);
INSERT INTO z1 VALUES('a', 'b', 'c');
INSERT INTO z1 VALUES('d', 'e', 'f');
INSERT INTO z1 VALUES('g', 'h', 'i');
-- INSERT INTO kk VALUES('y', 'y');
INSERT INTO kk VALUES('d', 'e');
-- INSERT INTO kk VALUES('x', 'x');
}
foreach {tn idx} {
1 { }
2 { CREATE INDEX z1idx ON z1(x, y) }
3 { CREATE UNIQUE INDEX z1idx ON z1(x, y) }
} {
execsql "DROP INDEX IF EXISTS z1idx"
execsql $idx
do_execsql_test 2.$tn.1 {
SELECT * FROM z1 WHERE x IN (SELECT a FROM kk)
} {d e f}
do_execsql_test 2.$tn.2 {
SELECT * FROM z1 WHERE (x,y) IN (SELECT a, b FROM kk)
} {d e f}
do_execsql_test 2.$tn.3 {
SELECT * FROM z1 WHERE (x, +y) IN (SELECT a, b FROM kk)
} {d e f}
do_execsql_test 2.$tn.4 {
SELECT * FROM z1 WHERE (x, +y) IN (SELECT a, b||'x' FROM kk)
} {}
do_execsql_test 2.$tn.5 {
SELECT * FROM z1 WHERE (+x, y) IN (SELECT a, b FROM kk)
} {d e f}
}
explain_i {
SELECT * FROM z1 WHERE (x, y) IN (SELECT a, b FROM kk)
}
finish_test finish_test

View File

@ -114,26 +114,22 @@ ifcapable {subquery && compound} {
CREATE TABLE t2(a,b); CREATE TABLE t2(a,b);
SELECT 5 IN (SELECT a,b FROM t2); SELECT 5 IN (SELECT a,b FROM t2);
} }
} [list 1 \ } {1 {sub-select returns 2 columns - expected 1}}
{only a single result allowed for a SELECT that is part of an expression}]
do_test select7-5.2 { do_test select7-5.2 {
catchsql { catchsql {
SELECT 5 IN (SELECT * FROM t2); SELECT 5 IN (SELECT * FROM t2);
} }
} [list 1 \ } {1 {sub-select returns 2 columns - expected 1}}
{only a single result allowed for a SELECT that is part of an expression}]
do_test select7-5.3 { do_test select7-5.3 {
catchsql { catchsql {
SELECT 5 IN (SELECT a,b FROM t2 UNION SELECT b,a FROM t2); SELECT 5 IN (SELECT a,b FROM t2 UNION SELECT b,a FROM t2);
} }
} [list 1 \ } {1 {sub-select returns 2 columns - expected 1}}
{only a single result allowed for a SELECT that is part of an expression}]
do_test select7-5.4 { do_test select7-5.4 {
catchsql { catchsql {
SELECT 5 IN (SELECT * FROM t2 UNION SELECT * FROM t2); SELECT 5 IN (SELECT * FROM t2 UNION SELECT * FROM t2);
} }
} [list 1 \ } {1 {sub-select returns 2 columns - expected 1}}
{only a single result allowed for a SELECT that is part of an expression}]
} }
# Verify that an error occurs if you have too many terms on a # Verify that an error occurs if you have too many terms on a

View File

@ -40,7 +40,7 @@ do_test subselect-1.1 {
do_test subselect-1.2 { do_test subselect-1.2 {
set v [catch {execsql {SELECT * FROM t1 WHERE a = (SELECT * FROM t1)}} msg] set v [catch {execsql {SELECT * FROM t1 WHERE a = (SELECT * FROM t1)}} msg]
lappend v $msg lappend v $msg
} {1 {only a single result allowed for a SELECT that is part of an expression}} } {1 {sub-select returns 2 columns - expected 1}}
# A subselect without an aggregate. # A subselect without an aggregate.
# #

View File

@ -1288,9 +1288,9 @@ proc explain_i {sql {db db}} {
set D "" set D ""
} }
foreach opcode { foreach opcode {
Seek SeekGe SeekGt SeekLe SeekLt NotFound Last Rewind Seek SeekGE SeekGT SeekLE SeekLT NotFound Last Rewind
NoConflict Next Prev VNext VPrev VFilter NoConflict Next Prev VNext VPrev VFilter
SorterSort SorterNext SorterSort SorterNext NextIfOpen
} { } {
set color($opcode) $B set color($opcode) $B
} }
@ -1311,9 +1311,15 @@ proc explain_i {sql {db db}} {
set bSeenGoto 1 set bSeenGoto 1
} }
if {$opcode=="Once"} {
for {set i $addr} {$i<$p2} {incr i} {
set star($i) $addr
}
}
if {$opcode=="Next" || $opcode=="Prev" if {$opcode=="Next" || $opcode=="Prev"
|| $opcode=="VNext" || $opcode=="VPrev" || $opcode=="VNext" || $opcode=="VPrev"
|| $opcode=="SorterNext" || $opcode=="SorterNext" || $opcode=="NextIfOpen"
} { } {
for {set i $p2} {$i<$addr} {incr i} { for {set i $p2} {$i<$addr} {incr i} {
incr x($i) 2 incr x($i) 2
@ -1337,6 +1343,12 @@ proc explain_i {sql {db db}} {
} }
set I [string repeat " " $x($addr)] set I [string repeat " " $x($addr)]
if {[info exists star($addr)]} {
set ii [expr $x($star($addr))]
append I " "
set I [string replace $I $ii $ii *]
}
set col "" set col ""
catch { set col $color($opcode) } catch { set col $color($opcode) }