From: drh Date: Fri, 10 Oct 2014 15:47:46 +0000 (+0000) Subject: Simplify the code used to generate the text for EXPLAIN QUERY PLAN. X-Git-Tag: version-3.8.7~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6c97789d2eb2df436506132cc3a4f211a68c6aa5;p=thirdparty%2Fsqlite.git Simplify the code used to generate the text for EXPLAIN QUERY PLAN. FossilOrigin-Name: beea1efc3a49cad08087fcbb18dbce71c873fe57 --- diff --git a/manifest b/manifest index a49120ba19..d11aa809a0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\spotential\sproblem\sin\sthe\swhereRangeScanEst()\sroutine\swhen\sSTAT4\sis\nactive.\s\sThe\sproblem\swas\sintroduced\sby\srecent\senhancements. -D 2014-10-10T15:01:46.922 +C Simplify\sthe\scode\sused\sto\sgenerate\sthe\stext\sfor\sEXPLAIN\sQUERY\sPLAN. +D 2014-10-10T15:47:46.266 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c d1e315e338f51e4e7ff83ac6231a81d1c0cd30f9 +F src/where.c 23b9e5dd96a51657fb7d81091c28cd84f54dc8a0 F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1203,7 +1203,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 177fff3b98b101b98f1e7d334b6a80530b645565 -R 07357edada657f8492081fa01ca31a82 +P 68e1b4de700b5291f79249a03e1a750c6b2c9ae4 +R 1d64962e74f9e7c1f94f06e344d62c75 U drh -Z a44558a0f7d62314eeda3bb13a5723b9 +Z 5a7fbeb924ed3728c1bc69e5188e226a diff --git a/manifest.uuid b/manifest.uuid index dc8efe9532..948793a5c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -68e1b4de700b5291f79249a03e1a750c6b2c9ae4 \ No newline at end of file +beea1efc3a49cad08087fcbb18dbce71c873fe57 \ No newline at end of file diff --git a/src/where.c b/src/where.c index e3ab542525..d1f379b6c3 100644 --- a/src/where.c +++ b/src/where.c @@ -2737,9 +2737,8 @@ static void explainAppendTerm( /* ** 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. +** function appends text to pStr that describes the subset of table +** rows scanned by the strategy in the form of an SQL expression. ** ** For example, if the query: ** @@ -2749,49 +2748,37 @@ static void explainAppendTerm( ** 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, WhereLoop *pLoop, Table *pTab){ +void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ Index *pIndex = pLoop->u.btree.pIndex; u16 nEq = pLoop->u.btree.nEq; u16 nSkip = pLoop->u.btree.nSkip; int i, j; Column *aCol = pTab->aCol; i16 *aiColumn = pIndex->aiColumn; - StrAccum txt; - if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ - return 0; - } - sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH); - txt.db = db; - sqlite3StrAccumAppend(&txt, " (", 2); + if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; + sqlite3StrAccumAppend(pStr, " (", 2); for(i=0; i=nSkip ){ - explainAppendTerm(&txt, i, z, "="); + explainAppendTerm(pStr, i, z, "="); }else{ - if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5); - sqlite3StrAccumAppend(&txt, "ANY(", 4); - sqlite3StrAccumAppendAll(&txt, z); - sqlite3StrAccumAppend(&txt, ")", 1); + if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5); + sqlite3XPrintf(pStr, 0, "ANY(%s)", z); } } j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(&txt, i++, z, ">"); + explainAppendTerm(pStr, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(&txt, i, z, "<"); + explainAppendTerm(pStr, i, z, "<"); } - sqlite3StrAccumAppend(&txt, ")", 1); - return sqlite3StrAccumFinish(&txt); + sqlite3StrAccumAppend(pStr, ")", 1); } /* @@ -2815,11 +2802,13 @@ static void explainOneScan( 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 */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ + char *zMsg; /* Text to add to EQP output */ + StrAccum str; /* EQP output string */ + char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; @@ -2829,54 +2818,65 @@ static void explainOneScan( || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); - zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN"); + sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + str.db = db; + sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId); + sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); }else{ - zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName); + sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); + sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); } - if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 - && ALWAYS(pLoop->u.btree.pIndex!=0) - ){ - const char *zFmt; - Index *pIdx = pLoop->u.btree.pIndex; - char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); + if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ + const char *zFmt = 0; + Index *pIdx; + + assert( pLoop->u.btree.pIndex!=0 ); + pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ - zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s"; + if( pLoop->u.btree.nEq>0 + || (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 + ){ + zFmt = "PRIMARY KEY"; + } }else if( flags & WHERE_AUTO_INDEX ){ - zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; + zFmt = "AUTOMATIC COVERING INDEX"; }else if( flags & WHERE_IDX_ONLY ){ - zFmt = "%s USING COVERING INDEX %s%s"; + zFmt = "COVERING INDEX %s"; }else{ - zFmt = "%s USING INDEX %s%s"; + zFmt = "INDEX %s"; + } + if( zFmt ){ + sqlite3StrAccumAppend(&str, " USING ", 7); + sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); + explainIndexRange(&str, pLoop, pItem->pTab); } - zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere); - sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); - + const char *zRange; if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); + zRange = "(rowid=?)"; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid? AND rowid?)", zMsg); - }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ - zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid?)"; + }else{ + assert( flags&WHERE_TOP_LIMIT); + zRange = "(rowidu.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif - zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg); + zMsg = sqlite3StrAccumFinish(&str); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } }