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:
34
manifest
34
manifest
@ -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
|
||||||
|
@ -1 +1 @@
|
|||||||
e2fd6f49b1b145bec09c581cc982b89429643ae9
|
061b8006034f06a0311b4304c8b14d2c8b0153df
|
50
src/expr.c
50
src/expr.c
@ -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: {
|
||||||
|
@ -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);
|
||||||
|
10
src/where.c
10
src/where.c
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
15
test/in.test
15
test/in.test
@ -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 {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
#
|
#
|
||||||
|
@ -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) }
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user