Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add missing comments and fix other issues with routines used by new EQP features. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | experimental |
Files: | files | file ages | folders |
SHA1: |
925f35c535396603e13bb12e9a361072 |
User & Date: | dan 2010-11-09 17:35:20.000 |
Context
2010-11-09
| ||
17:49 | Merge with latest trunk changes. (check-in: 4b5c93bc7c user: dan tags: experimental) | |
17:35 | Add missing comments and fix other issues with routines used by new EQP features. (check-in: 925f35c535 user: dan tags: experimental) | |
14:49 | Further enhancements and fixes for explain query plan. (check-in: 73c93f5a2a user: dan tags: experimental) | |
Changes
Changes to src/select.c.
︙ | ︙ | |||
768 769 770 771 772 773 774 775 776 777 778 779 780 781 | pInfo->aSortOrder[i] = pItem->sortOrder; } } return pInfo; } #ifndef SQLITE_OMIT_EXPLAIN static void explainTempTable(Parse *pParse, const char *zUsage){ if( pParse->explain==2 ){ Vdbe *v = pParse->pVdbe; char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); } } | > > > > > > > > > > | > > > > > > > > | | | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | pInfo->aSortOrder[i] = pItem->sortOrder; } } return pInfo; } #ifndef SQLITE_OMIT_EXPLAIN /* ** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function ** is a no-op. Otherwise, it adds a single row of output to the EQP result, ** where the caption is of the form: ** ** "USE TEMP B-TREE FOR xxx" ** ** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which ** is determined by the zUsage argument. */ static void explainTempTable(Parse *pParse, const char *zUsage){ if( pParse->explain==2 ){ Vdbe *v = pParse->pVdbe; char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); } } /* ** Assign expression b to lvalue a. A second, no-op, version of this macro ** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code ** in sqlite3Select() to assign values to structure member variables that ** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the ** code with #ifndef directives. */ # define explainSetInteger(a, b) a = b #else /* No-op versions of the explainXXX() functions and macros. */ # define explainTempTable(y,z) # define explainSetInteger(y,z) #endif /* ** If the inner loop was generated using a non-null pOrderBy argument, ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following ** routine generates the code needed to do that. |
︙ | ︙ | |||
3677 3678 3679 3680 3681 3682 3683 | isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); assert( pItem->isPopulated==0 ); | | | 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 | isAgg = 1; p->selFlags |= SF_Aggregate; } i = -1; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); assert( pItem->isPopulated==0 ); explainSetInteger(pItem->iSelectId, pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); pItem->isPopulated = 1; } if( /*pParse->nErr ||*/ db->mallocFailed ){ goto select_end; } pParse->nHeight -= sqlite3SelectExprHeight(p); |
︙ | ︙ | |||
3716 3717 3718 3719 3720 3721 3722 | } mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT]; if( mxSelect && cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); goto select_end; } } | | | 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 | } mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT]; if( mxSelect && cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); goto select_end; } } explainSetInteger(pParse->iSelectId, iRestoreSelectId); return multiSelect(pParse, p, pDest); } #endif /* If possible, rewrite the query to use GROUP BY instead of DISTINCT. ** GROUP BY might use an index, DISTINCT never does. */ |
︙ | ︙ | |||
4223 4224 4225 4226 4227 4228 4229 | */ rc = 0; /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. */ select_end: | | | 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 | */ rc = 0; /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. */ select_end: explainSetInteger(pParse->iSelectId, iRestoreSelectId); /* Identify column names if results of the SELECT are to be output. */ if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){ generateColumnNames(pParse, pTabList, pEList); } |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
3127 3128 3129 3130 3131 3132 3133 | } } *pzAff = zAff; return regBase; } #ifndef SQLITE_OMIT_EXPLAIN | > > > > > > > > > > > > > > > > > > > | | 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 | } } *pzAff = zAff; return regBase; } #ifndef SQLITE_OMIT_EXPLAIN /* ** Argument pLevel describes a strategy for scanning table pTab. This ** function returns a pointer to a string buffer containing a description ** of the subset of table rows scanned by the strategy in the form of an ** SQL expression. Or, if all rows are scanned, NULL is returned. ** ** For example, if the query: ** ** SELECT * FROM t1 WHERE a=1 AND b>2; ** ** is run and there is an index on (a, b), then this function returns a ** string similar to: ** ** "a=? AND b>?" ** ** The returned pointer points to memory obtained from sqlite3DbMalloc(). ** It is the responsibility of the caller to free the buffer when it is ** no longer required. */ static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){ WherePlan *pPlan = &pLevel->plan; Index *pIndex = pPlan->u.pIdx; int nEq = pPlan->nEq; char *zRet = 0; int i; for(i=0; i<nEq; i++){ |
︙ | ︙ | |||
3156 3157 3158 3159 3160 3161 3162 | if( zRet ){ zRet = sqlite3MAppendf(db, zRet, " (%s)", zRet); } return zRet; } | > > > > > > | | | | | | 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 | if( zRet ){ zRet = sqlite3MAppendf(db, zRet, " (%s)", zRet); } return zRet; } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN ** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single ** record is added to the output to describe the table scan strategy in ** pLevel. */ static void explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ int iLevel, /* Value for "level" column of output */ int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ if( pParse->explain==2 ){ u32 flags = pLevel->plan.wsFlags; struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ char *zMsg; /* Text to add to EQP output */ sqlite3_int64 nRow; /* Expected number of rows visited by scan */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; if( pItem->pSelect ){ zMsg = sqlite3MPrintf(db, "SCAN SUBQUERY %d", pItem->iSelectId); }else{ zMsg = sqlite3MPrintf(db, "SCAN TABLE %s", pItem->zName); } if( pItem->zAlias ){ zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); } if( (flags & WHERE_INDEXED)!=0 ){ char *zWhere = explainIndexRange(db, pLevel, pItem->pTab); zMsg = sqlite3MAppendf(db, zMsg, "%s BY %s%sINDEX%s%s%s", zMsg, ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""), ((flags & WHERE_IDX_ONLY)?"COVERING ":""), ((flags & WHERE_TEMP_INDEX)?"":" "), ((flags & WHERE_TEMP_INDEX)?"": pLevel->plan.u.pIdx->zName), zWhere ); |
︙ | ︙ | |||
3224 3225 3226 3227 3228 3229 3230 | nRow = (sqlite3_int64)pLevel->plan.nRow; } zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } #else | | | 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 | nRow = (sqlite3_int64)pLevel->plan.nRow; } zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } #else # define explainOneScan(u,v,w,x,y,z) #endif /* SQLITE_OMIT_EXPLAIN */ /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ |
︙ | ︙ | |||
3769 3770 3771 3772 3773 3774 3775 | if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); if( pSubWInfo ){ | | | 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 | if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0, WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); if( pSubWInfo ){ explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); int r; r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, regRowid); |
︙ | ︙ | |||
4428 4429 4430 4431 4432 4433 4434 | /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(i=0; i<nTabList; i++){ WhereLevel *pLevel = &pWInfo->a[i]; | | | 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 | /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(i=0; i<nTabList; i++){ WhereLevel *pLevel = &pWInfo->a[i]; explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags); notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady); pWInfo->iContinue = pLevel->addrCont; } #ifdef SQLITE_TEST /* For testing and debugging use only */ /* Record in the query plan information about the current table ** and the index used to access it (if any). If the table itself |
︙ | ︙ |