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:
12
manifest
12
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.
|
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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
68e1b4de700b5291f79249a03e1a750c6b2c9ae4
|
beea1efc3a49cad08087fcbb18dbce71c873fe57
|
||||||
100
src/where.c
100
src/where.c
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user