1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-18 10:21:03 +03:00

Simplify the code used to generate the text for EXPLAIN QUERY PLAN.

FossilOrigin-Name: beea1efc3a49cad08087fcbb18dbce71c873fe57
This commit is contained in:
drh
2014-10-10 15:47:46 +00:00
parent 681fca0018
commit 6c97789d2e
3 changed files with 57 additions and 57 deletions

View File

@@ -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. C Simplify\sthe\scode\sused\sto\sgenerate\sthe\stext\sfor\sEXPLAIN\sQUERY\sPLAN.
D 2014-10-10T15:01:46.922 D 2014-10-10T15:47:46.266
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f
F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c d1e315e338f51e4e7ff83ac6231a81d1c0cd30f9 F src/where.c 23b9e5dd96a51657fb7d81091c28cd84f54dc8a0
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -1203,7 +1203,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 177fff3b98b101b98f1e7d334b6a80530b645565 P 68e1b4de700b5291f79249a03e1a750c6b2c9ae4
R 07357edada657f8492081fa01ca31a82 R 1d64962e74f9e7c1f94f06e344d62c75
U drh U drh
Z a44558a0f7d62314eeda3bb13a5723b9 Z 5a7fbeb924ed3728c1bc69e5188e226a

View File

@@ -1 +1 @@
68e1b4de700b5291f79249a03e1a750c6b2c9ae4 beea1efc3a49cad08087fcbb18dbce71c873fe57

View File

@@ -2737,9 +2737,8 @@ static void explainAppendTerm(
/* /*
** Argument pLevel describes a strategy for scanning table pTab. This ** Argument pLevel describes a strategy for scanning table pTab. This
** function returns a pointer to a string buffer containing a description ** function appends text to pStr that describes the subset of table
** of the subset of table rows scanned by the strategy in the form of an ** rows scanned by the strategy in the form of an SQL expression.
** SQL expression. Or, if all rows are scanned, NULL is returned.
** **
** For example, if the query: ** For example, if the query:
** **
@@ -2749,49 +2748,37 @@ static void explainAppendTerm(
** string similar to: ** string similar to:
** **
** "a=? AND b>?" ** "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; Index *pIndex = pLoop->u.btree.pIndex;
u16 nEq = pLoop->u.btree.nEq; u16 nEq = pLoop->u.btree.nEq;
u16 nSkip = pLoop->u.btree.nSkip; u16 nSkip = pLoop->u.btree.nSkip;
int i, j; int i, j;
Column *aCol = pTab->aCol; Column *aCol = pTab->aCol;
i16 *aiColumn = pIndex->aiColumn; i16 *aiColumn = pIndex->aiColumn;
StrAccum txt;
if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){ if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
return 0; sqlite3StrAccumAppend(pStr, " (", 2);
}
sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
txt.db = db;
sqlite3StrAccumAppend(&txt, " (", 2);
for(i=0; i<nEq; i++){ for(i=0; i<nEq; i++){
char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName; char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
if( i>=nSkip ){ if( i>=nSkip ){
explainAppendTerm(&txt, i, z, "="); explainAppendTerm(pStr, i, z, "=");
}else{ }else{
if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5); if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
sqlite3StrAccumAppend(&txt, "ANY(", 4); sqlite3XPrintf(pStr, 0, "ANY(%s)", z);
sqlite3StrAccumAppendAll(&txt, z);
sqlite3StrAccumAppend(&txt, ")", 1);
} }
} }
j = i; j = i;
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
explainAppendTerm(&txt, i++, z, ">"); explainAppendTerm(pStr, i++, z, ">");
} }
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
explainAppendTerm(&txt, i, z, "<"); explainAppendTerm(pStr, i, z, "<");
} }
sqlite3StrAccumAppend(&txt, ")", 1); sqlite3StrAccumAppend(pStr, ")", 1);
return sqlite3StrAccumFinish(&txt);
} }
/* /*
@@ -2815,11 +2802,13 @@ static void explainOneScan(
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
Vdbe *v = pParse->pVdbe; /* VM being constructed */ Vdbe *v = pParse->pVdbe; /* VM being constructed */
sqlite3 *db = pParse->db; /* Database handle */ 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 iId = pParse->iSelectId; /* Select id (left-most output column) */
int isSearch; /* True for a SEARCH. False for SCAN. */ int isSearch; /* True for a SEARCH. False for SCAN. */
WhereLoop *pLoop; /* The controlling WhereLoop object */ WhereLoop *pLoop; /* The controlling WhereLoop object */
u32 flags; /* Flags that describe this loop */ 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; pLoop = pLevel->pWLoop;
flags = pLoop->wsFlags; flags = pLoop->wsFlags;
@@ -2829,54 +2818,65 @@ static void explainOneScan(
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); || (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 ){ if( pItem->pSelect ){
zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId); sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
}else{ }else{
zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName); sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
} }
if( pItem->zAlias ){ 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 if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
&& ALWAYS(pLoop->u.btree.pIndex!=0) const char *zFmt = 0;
){ Index *pIdx;
const char *zFmt;
Index *pIdx = pLoop->u.btree.pIndex; assert( pLoop->u.btree.pIndex!=0 );
char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); pIdx = pLoop->u.btree.pIndex;
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ 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 ){ }else if( flags & WHERE_AUTO_INDEX ){
zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s"; zFmt = "AUTOMATIC COVERING INDEX";
}else if( flags & WHERE_IDX_ONLY ){ }else if( flags & WHERE_IDX_ONLY ){
zFmt = "%s USING COVERING INDEX %s%s"; zFmt = "COVERING INDEX %s";
}else{ }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 ){ }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) ){ 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 ){ }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg); zRange = "(rowid>? AND rowid<?)";
}else if( flags&WHERE_BTM_LIMIT ){ }else if( flags&WHERE_BTM_LIMIT ){
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg); zRange = "(rowid>?)";
}else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){ }else{
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg); assert( flags&WHERE_TOP_LIMIT);
zRange = "(rowid<?)";
} }
sqlite3StrAccumAppendAll(&str, " USING INTEGER PRIMARY KEY ");
sqlite3StrAccumAppendAll(&str, zRange);
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg, sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
} }
#endif #endif
zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg); zMsg = sqlite3StrAccumFinish(&str);
sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
} }
} }