Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Do not allow cursor hints to use expressions containing subqueries. This change fixes the problem seen in the previous check-in. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | cursor-hints |
Files: | files | file ages | folders |
SHA1: |
bfefc57554853e467ee6aeaba8d08331 |
User & Date: | drh 2013-12-07 23:35:21.843 |
Context
2014-07-14
| ||
19:04 | In the expression passed to sqlite3BtreeCursorHint() for the inner loops of joins, replace any TK_COLUMN references to columns in the outer loops with TK_REGISTER expressions (Expr.iTable indicates the specific register containing the value). There are no automated tests for this yet. (check-in: f9dddd008c user: dan tags: cursor-hints) | |
2013-12-07
| ||
23:35 | Do not allow cursor hints to use expressions containing subqueries. This change fixes the problem seen in the previous check-in. (check-in: bfefc57554 user: drh tags: cursor-hints) | |
20:39 | If the SQLITE_ENABLE_CURSOR_HINTS macro is defined, then invoke the sqlite3BtreeCursorHint() interface to provide hints to the storage engine about rows that need not be returned. Hints can be disabled using SQLITE_TESTCTRL_OPTIMIZATIONS with SQLITE_CursorHints (0x2000). Cursor hints are not used by the built-in storage engine of SQLite but might be useful to applications that provide their own storage engine. The current code is work-in-progrss and contains bugs. (check-in: 3a9bec524e user: drh tags: cursor-hints) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 | ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ int sqlite3ExprIsConstantOrFunction(Expr *p){ return exprIsConst(p, 2); } /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ | > > > > > > > > > > > > > > > > | 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 | ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ int sqlite3ExprIsConstantOrFunction(Expr *p){ return exprIsConst(p, 2); } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Walk an expression tree. Return 1 if the expression contains a ** subquery of some kind. Return 0 if there are no subqueries. */ int sqlite3ExprContainsSubquery(Expr *p){ Walker w; memset(&w, 0, sizeof(w)); w.u.i = 1; w.xExprCallback = sqlite3ExprWalkNoop; w.xSelectCallback = selectNodeIsConstant; sqlite3WalkExpr(&w, p); return w.u.i==0; } #endif /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
3685 3686 3687 3688 3689 3690 3691 | ** ** When this routine is the Walker.xExprCallback then expression trees ** are walked without any actions being taken at each node. Presumably, ** when this routine is used for Walker.xExprCallback then ** Walker.xSelectCallback is set to do something useful for every ** subquery in the parser tree. */ | | | | 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 | ** ** When this routine is the Walker.xExprCallback then expression trees ** are walked without any actions being taken at each node. Presumably, ** when this routine is used for Walker.xExprCallback then ** Walker.xSelectCallback is set to do something useful for every ** subquery in the parser tree. */ int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return WRC_Continue; } /* ** This routine "expands" a SELECT statement and all of its subqueries. ** For additional information on what it means to "expand" a SELECT ** statement, see the comment on the selectExpand worker callback above. ** ** Expanding a SELECT statement is the first step in processing a ** SELECT statement. The SELECT statement must be expanded before ** name resolution is performed. ** ** If anything goes wrong, an error message is written into pParse. ** The calling function can detect the problem by looking at pParse->nErr ** and/or pParse->db->mallocFailed. */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; if( pParse->hasCompound ){ w.xSelectCallback = convertCompoundSelectToSubquery; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; sqlite3WalkSelect(&w, pSelect); |
︙ | ︙ | |||
3770 3771 3772 3773 3774 3775 3776 | ** Use this routine after name resolution. */ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; memset(&w, 0, sizeof(w)); w.xSelectCallback = selectAddSubqueryTypeInfo; | | | 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 | ** Use this routine after name resolution. */ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; memset(&w, 0, sizeof(w)); w.xSelectCallback = selectAddSubqueryTypeInfo; w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; w.bSelectDepthFirst = 1; sqlite3WalkSelect(&w, pSelect); #endif } |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 | /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); int sqlite3WalkSelectExpr(Walker*, Select*); int sqlite3WalkSelectFrom(Walker*, Select*); /* ** Return code from the parse-tree walking primitives and their ** callbacks. */ #define WRC_Continue 0 /* Continue down into children */ #define WRC_Prune 1 /* Omit children but continue walking siblings */ | > | 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 | /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); int sqlite3WalkSelectExpr(Walker*, Select*); int sqlite3WalkSelectFrom(Walker*, Select*); int sqlite3ExprWalkNoop(Walker*, Expr*); /* ** Return code from the parse-tree walking primitives and their ** callbacks. */ #define WRC_Continue 0 /* Continue down into children */ #define WRC_Prune 1 /* Omit children but continue walking siblings */ |
︙ | ︙ | |||
2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 | void sqlite3RollbackTransaction(Parse*); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); | > | 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 | void sqlite3RollbackTransaction(Parse*); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprContainsSubquery(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 | iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; msk = ~getMask(&pWInfo->sMaskSet, iCur); pWC = &pWInfo->sWC; for(i=0; i<pWC->nTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->prereqAll & msk ) continue; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){} if( j<pWLoop->nLTerm ) continue; pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, (const char*)pExpr, P4_EXPR); | > | 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 | iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; msk = ~getMask(&pWInfo->sMaskSet, iCur); pWC = &pWInfo->sWC; for(i=0; i<pWC->nTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->prereqAll & msk ) continue; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue; for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){} if( j<pWLoop->nLTerm ) continue; pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, (const char*)pExpr, P4_EXPR); |
︙ | ︙ |