Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | rowvalue |
Files: | files | file ages | folders |
SHA1: |
061b8006034f06a0311b4304c8b14d2c |
User & Date: | dan 2016-07-26 18:06:08.100 |
References
2016-09-16
| ||
13:57 | • New ticket [0eab1ac759] O(N*N) behavior where it should be O(N). (artifact: 62ca7f9b91 user: drh) | |
Context
2016-07-26
| ||
18:15 | Merge latest trunk changes into this branch. (check-in: d4f3d52c5a user: dan tags: rowvalue) | |
18:06 | 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. (check-in: 061b800603 user: dan tags: rowvalue) | |
2016-07-23
| ||
20:24 | Allow vector IN(SELECT ...) expressions to use an index if either all the indexed columns are declared NOT NULL or if there is no difference between the expression evaluating to 0 and NULL (as in a WHERE clause). (check-in: e2fd6f49b1 user: dan tags: rowvalue) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
334 335 336 337 338 339 340 341 342 343 344 345 346 347 | assert( i==0 ); return pVector; }else if( pVector->flags & EP_xIsSelect ){ return pVector->x.pSelect->pEList->a[i].pExpr; } return pVector->x.pList->a[i].pExpr; } static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){ Vdbe *v = pParse->pVdbe; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int nRight = sqlite3ExprVectorSize(pRight); | > > > > > > > > > > > > > | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | assert( i==0 ); return pVector; }else if( pVector->flags & EP_xIsSelect ){ return pVector->x.pSelect->pEList->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){ Vdbe *v = pParse->pVdbe; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int nRight = sqlite3ExprVectorSize(pRight); |
︙ | ︙ | |||
385 386 387 388 389 390 391 | case TK_GE: opCmp = OP_Cmp; opTest = OP_CmpTest; p3 = pExpr->op; break; } | < < | < < < < | < < | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | case TK_GE: opCmp = OP_Cmp; opTest = OP_CmpTest; p3 = pExpr->op; break; } regLeft = exprVectorSubselect(pParse, pLeft); regRight = exprVectorSubselect(pParse, pRight); if( pParse->nErr ) return; for(i=0; i<nLeft; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL, *pR; int r1, r2; |
︙ | ︙ | |||
2060 2061 2062 2063 2064 2065 2066 | zRet = sqlite3DbMallocZero(pParse->db, nVal+1); if( zRet ){ int i; for(i=0; i<nVal; i++){ Expr *pA; char a; | | > > > > > > > > > > > > > | 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 | zRet = sqlite3DbMallocZero(pParse->db, nVal+1); if( zRet ){ int i; for(i=0; i<nVal; i++){ Expr *pA; char a; if( nVal==1 && 0 ){ pA = pLeft; }else{ pA = exprVectorField(pLeft, i); } a = sqlite3ExprAffinity(pA); zRet[i] = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[i].pExpr, a); } zRet[nVal] = '\0'; } 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, ** or IN operators. Examples: ** ** (SELECT a FROM b) -- subquery ** EXISTS (SELECT a FROM b) -- EXISTS subquery |
︙ | ︙ | |||
2176 2177 2178 2179 2180 2181 2182 | ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; assert( !isRowid ); if( pEList->nExpr!=nVal ){ | < | | 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 | ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; assert( !isRowid ); if( pEList->nExpr!=nVal ){ sqlite3SubselectError(pParse, pEList->nExpr, nVal); }else{ SelectDest dest; int i; sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.zAffSdst = exprINAffinity(pParse, pExpr); assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pSelect->iLimit = 0; |
︙ | ︙ | |||
3346 3347 3348 3349 3350 3351 3352 3353 3354 | sqlite3ReleaseTempRange(pParse, r1, nFarg); } break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); | > > > > | > | 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 | sqlite3ReleaseTempRange(pParse, r1, nFarg); } break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { int nCol; testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ sqlite3SubselectError(pParse, nCol, 1); }else{ inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); } break; } case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(v); int destIfNull = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
763 764 765 766 767 768 769 | assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); pNC->ncFlags |= NC_VarSelect; } if( pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1 ){ | | | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); pNC->ncFlags |= NC_VarSelect; } if( pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1 ){ if( !ExprHasProperty(pExpr, EP_VectorOk) && 0 ){ sqlite3ErrorMsg(pParse, "invalid use of row value"); }else{ ExprSetProperty(pExpr, EP_Vector); } } if( pExpr->op==TK_IN ){ ExprSetProperty(pExpr->pLeft, EP_VectorOk); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
4709 4710 4711 4712 4713 4714 4715 | } if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); | > | | | | > | 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 | } if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); VdbeCoverage(v); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); } sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); if( pLevel->addrSkip ){ sqlite3VdbeGoto(v, pLevel->addrSkip); VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); |
︙ | ︙ |
Changes to src/whereInt.h.
︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 253 254 255 256 257 | ** in prereqRight and prereqAll. The default is 64 bits, hence SQLite ** is only able to process joins with 64 or fewer tables. */ struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */ union { int leftColumn; /* Column number of X in "X <op> <expr>" */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; LogEst truthProb; /* Probability of truth for this expression */ u16 eOperator; /* A WO_xx value describing <op> */ | > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | ** in prereqRight and prereqAll. The default is 64 bits, hence SQLite ** is only able to process joins with 64 or fewer tables. */ struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */ int iField; /* Field in (?,?,?) IN (SELECT...) vector */ union { int leftColumn; /* Column number of X in "X <op> <expr>" */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; LogEst truthProb; /* Probability of truth for this expression */ u16 eOperator; /* A WO_xx value describing <op> */ |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | int bRev, /* True for reverse-order IN operations */ int iTarget /* Attempt to leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; int iReg; /* Register holding results */ assert( iTarget>0 ); if( pX->op==TK_EQ || pX->op==TK_IS ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; int iTab; struct InLoop *pIn; WhereLoop *pLoop = pLevel->pWLoop; if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 && pLoop->u.btree.pIndex->aSortOrder[iEq] ){ testcase( iEq==0 ); testcase( bRev ); bRev = !bRev; } assert( pX->op==TK_IN ); iReg = iTarget; | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > | > | | > > | | > > | > > > > | > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | int bRev, /* True for reverse-order IN operations */ int iTarget /* Attempt to leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; int iReg; /* Register holding results */ assert( pLevel->pWLoop->aLTerm[iEq]==pTerm ); assert( iTarget>0 ); if( pX->op==TK_EQ || pX->op==TK_IS ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; int iTab; struct InLoop *pIn; WhereLoop *pLoop = pLevel->pWLoop; int i; int nEq = 0; int *aiMap = 0; if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 && pLoop->u.btree.pIndex->aSortOrder[iEq] ){ testcase( iEq==0 ); testcase( bRev ); bRev = !bRev; } assert( pX->op==TK_IN ); iReg = iTarget; 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 ){ testcase( bRev ); bRev = !bRev; } iTab = pX->iTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } i = pLevel->u.in.nIn; pLevel->u.in.nIn += nEq; pLevel->u.in.aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); pIn = pLevel->u.in.aInLoop; if( pIn ){ int iMap = 0; /* Index in aiMap[] */ pIn += i; for(i=iEq;i<pLoop->nLTerm; i++, pIn++){ if( pLoop->aLTerm[i]->pExpr==pX ){ if( eType==IN_INDEX_ROWID ){ 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); } }else{ pLevel->u.in.nIn = 0; } sqlite3DbFree(pParse->db, aiMap); #endif } disableTerm(pLevel, pTerm); return iReg; } /* |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
956 957 958 959 960 961 962 963 964 965 966 967 968 969 | pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ int iCur, iColumn; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){ pTerm->leftCursor = iCur; pTerm->u.leftColumn = iColumn; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight | > > > > > > | 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ int iCur, iColumn; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); 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) ){ pTerm->leftCursor = iCur; pTerm->u.leftColumn = iColumn; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 | int idxNew; Expr *pNew; Expr *pLeft = exprVectorExpr(pParse, pExpr->pLeft, i); Expr *pRight = exprVectorExpr(pParse, pExpr->pRight, i); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0); idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* When sqlite_stat3 histogram data is available an operator of the | > > > > > > > > > > > > > | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 | int idxNew; Expr *pNew; Expr *pLeft = exprVectorExpr(pParse, pExpr->pLeft, i); Expr *pRight = exprVectorExpr(pParse, pExpr->pRight, i); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0); idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } } 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 /* When sqlite_stat3 histogram data is available an operator of the |
︙ | ︙ |
Changes to test/e_expr.test.
︙ | ︙ | |||
1805 1806 1807 1808 1809 1810 1811 | # EVIDENCE-OF: R-46899-53765 A SELECT used as a scalar quantity must # return a result set with a single column. # # The following block tests that errors are returned in a bunch of cases # where a subquery returns more than one column. # | | | | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 | # EVIDENCE-OF: R-46899-53765 A SELECT used as a scalar quantity must # return a result set with a single column. # # The following block tests that errors are returned in a bunch of cases # where a subquery returns more than one column. # set M {/1 {sub-select returns [23] columns - expected 1}/} foreach {tn sql} { 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) } 3 { SELECT (SELECT 1, 2) } 4 { SELECT (SELECT NULL, NULL, NULL) } 5 { SELECT (SELECT * FROM t2) } 6 { SELECT (SELECT * FROM (SELECT 1, 2, 3)) } } { do_catchsql_test e_expr-35.2.$tn $sql $M } # EVIDENCE-OF: R-35764-28041 The result of the expression is the value # of the only column in the first row returned by the SELECT statement. # # EVIDENCE-OF: R-41898-06686 If the SELECT yields more than one result # row, all rows after the first are ignored. |
︙ | ︙ |
Changes to test/in.test.
︙ | ︙ | |||
310 311 312 313 314 315 316 | SELECT b FROM t1 WHERE a NOT IN t4; } } {64 256 world} do_test in-9.4 { catchsql { SELECT b FROM t1 WHERE a NOT IN tb; } | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | SELECT b FROM t1 WHERE a NOT IN t4; } } {64 256 world} do_test in-9.4 { catchsql { SELECT b FROM t1 WHERE a NOT IN tb; } } {1 {sub-select returns 2 columns - expected 1}} # IN clauses in CHECK constraints. Ticket #1645 # do_test in-10.1 { execsql { CREATE TABLE t5( a INTEGER, |
︙ | ︙ | |||
387 388 389 390 391 392 393 | } {} do_test in-12.2 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2 ); } | | | | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | } {} do_test in-12.2 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2 ); } } {1 {sub-select returns 2 columns - expected 1}} do_test in-12.3 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION SELECT a, b FROM t2 ); } } {1 {sub-select returns 2 columns - expected 1}} do_test in-12.4 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 EXCEPT SELECT a, b FROM t2 ); } } {1 {sub-select returns 2 columns - expected 1}} do_test in-12.5 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 INTERSECT SELECT a, b FROM t2 ); } } {1 {sub-select returns 2 columns - expected 1}} do_test in-12.6 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION ALL SELECT a FROM t2 ); } } {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}} |
︙ | ︙ | |||
474 475 476 477 478 479 480 | } {1 {SELECTs to the left and right of INTERSECT do not have the same number of result columns}} do_test in-12.14 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2 ); } | | | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | } {1 {SELECTs to the left and right of INTERSECT do not have the same number of result columns}} do_test in-12.14 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION ALL SELECT a, b FROM t2 ); } } {1 {sub-select returns 2 columns - expected 1}} do_test in-12.15 { catchsql { SELECT * FROM t2 WHERE a IN ( SELECT a, b FROM t3 UNION ALL SELECT a FROM t2 ); } } {1 {SELECTs to the left and right of UNION ALL do not have the same number of result columns}} |
︙ | ︙ | |||
625 626 627 628 629 630 631 632 633 634 635 | do_test in-13.14 { execsql { CREATE INDEX i5 ON b(id); SELECT * FROM a WHERE id NOT IN (SELECT id FROM b); } } {} do_test in-13.15 { catchsql { SELECT 0 WHERE (SELECT 0,0) OR (0 IN (1,2)); } | > | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | do_test in-13.14 { execsql { CREATE INDEX i5 ON b(id); SELECT * FROM a WHERE id NOT IN (SELECT id FROM b); } } {} breakpoint do_test in-13.15 { catchsql { SELECT 0 WHERE (SELECT 0,0) OR (0 IN (1,2)); } } {1 {sub-select returns 2 columns - expected 1}} do_test in-13.X { db nullvalue "" } {} finish_test |
Changes to test/rowvalue3.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 | 9 "SELECT (1, 2) IN (SELECT rowid, b FROM t1)" 1 10 "SELECT 1 WHERE (1, 2) IN (SELECT rowid, b FROM t1)" 1 11 "SELECT 1 WHERE (1, NULL) IN (SELECT rowid, b FROM t1)" {} } { do_execsql_test 1.$tn $sql $res } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > | > > > > > > | > > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 9 "SELECT (1, 2) IN (SELECT rowid, b FROM t1)" 1 10 "SELECT 1 WHERE (1, 2) IN (SELECT rowid, b FROM t1)" 1 11 "SELECT 1 WHERE (1, NULL) IN (SELECT rowid, b FROM t1)" {} } { do_execsql_test 1.$tn $sql $res } #------------------------------------------------------------------------- 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 |
Changes to test/select7.test.
︙ | ︙ | |||
110 111 112 113 114 115 116 | # ifcapable {subquery && compound} { do_test select7-5.1 { catchsql { CREATE TABLE t2(a,b); SELECT 5 IN (SELECT a,b FROM t2); } | | < | < | < | < | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | # ifcapable {subquery && compound} { do_test select7-5.1 { catchsql { CREATE TABLE t2(a,b); SELECT 5 IN (SELECT a,b FROM t2); } } {1 {sub-select returns 2 columns - expected 1}} do_test select7-5.2 { catchsql { SELECT 5 IN (SELECT * FROM t2); } } {1 {sub-select returns 2 columns - expected 1}} do_test select7-5.3 { catchsql { SELECT 5 IN (SELECT a,b FROM t2 UNION SELECT b,a FROM t2); } } {1 {sub-select returns 2 columns - expected 1}} do_test select7-5.4 { catchsql { SELECT 5 IN (SELECT * FROM t2 UNION SELECT * FROM t2); } } {1 {sub-select returns 2 columns - expected 1}} } # Verify that an error occurs if you have too many terms on a # compound select statement. # if {[clang_sanitize_address]==0} { ifcapable compound { |
︙ | ︙ |
Changes to test/subselect.test.
︙ | ︙ | |||
36 37 38 39 40 41 42 | } {3 4} # Try a select with more than one result column. # do_test subselect-1.2 { set v [catch {execsql {SELECT * FROM t1 WHERE a = (SELECT * FROM t1)}} msg] lappend v $msg | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | } {3 4} # Try a select with more than one result column. # do_test subselect-1.2 { set v [catch {execsql {SELECT * FROM t1 WHERE a = (SELECT * FROM t1)}} msg] lappend v $msg } {1 {sub-select returns 2 columns - expected 1}} # A subselect without an aggregate. # do_test subselect-1.3a { execsql {SELECT b from t1 where a = (SELECT a FROM t1 WHERE b=2)} } {2} do_test subselect-1.3b { |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 | } else { set R "" set G "" set B "" set D "" } foreach opcode { | | | > > > > > > | | 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 | } else { set R "" set G "" set B "" set D "" } foreach opcode { Seek SeekGE SeekGT SeekLE SeekLT NotFound Last Rewind NoConflict Next Prev VNext VPrev VFilter SorterSort SorterNext NextIfOpen } { set color($opcode) $B } foreach opcode {ResultRow} { set color($opcode) $G } foreach opcode {IdxInsert Insert Delete IdxDelete} { set color($opcode) $R } set bSeenGoto 0 $db eval "explain $sql" {} { set x($addr) 0 set op($addr) $opcode if {$opcode == "Goto" && ($bSeenGoto==0 || ($p2 > $addr+10))} { set linebreak($p2) 1 set bSeenGoto 1 } if {$opcode=="Once"} { for {set i $addr} {$i<$p2} {incr i} { set star($i) $addr } } if {$opcode=="Next" || $opcode=="Prev" || $opcode=="VNext" || $opcode=="VPrev" || $opcode=="SorterNext" || $opcode=="NextIfOpen" } { for {set i $p2} {$i<$addr} {incr i} { incr x($i) 2 } } if {$opcode == "Goto" && $p2<$addr && $op($p2)=="Yield"} { |
︙ | ︙ | |||
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | } $db eval "explain $sql" {} { if {[info exists linebreak($addr)]} { output2 "" } set I [string repeat " " $x($addr)] set col "" catch { set col $color($opcode) } output2 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment ] | > > > > > > | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 | } $db eval "explain $sql" {} { if {[info exists linebreak($addr)]} { output2 "" } 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 "" catch { set col $color($opcode) } output2 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment ] |
︙ | ︙ |