Enable SELECT query planning tracing when compiled with
SQLITE_ENABLE_SELECTTRACE and either SQLITE_DEBUG or SQLITE_TEST.
FossilOrigin-Name: cbe0cf9ddf46f0a678c85d49bfa74e3b7712e1a1
diff --git a/src/parse.y b/src/parse.y
index dbc129c..45e6fae 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -459,9 +459,33 @@
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
%endif SQLITE_OMIT_COMPOUND_SELECT
-oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
+oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
+#if SELECTTRACE_ENABLED
+ /* Populate the Select.zSelLabel[] string that is used to help with
+ ** query planner debugging, to differentiate between multiple Select
+ ** objects in a complex query.
+ **
+ ** If the SELECT keyword is immediately followed by a C-style comment
+ ** then extract the first few alphanumeric characters from within that
+ ** comment to be the zSelLabel value. Otherwise, the label is #N where
+ ** is an integer that is incremented with each SELECT statement seen.
+ */
+ if( A!=0 ){
+ const char *z = S.z+6;
+ int i;
+ sqlite3_snprintf(sizeof(A->zSelLabel), A->zSelLabel, "#%d",
+ ++pParse->nSelect);
+ while( z[0]==' ' ) z++;
+ if( z[0]=='/' && z[1]=='*' ){
+ z += 2;
+ while( z[0]==' ' ) z++;
+ for(i=0; sqlite3Isalnum(z[i]); i++){}
+ sqlite3_snprintf(sizeof(A->zSelLabel), A->zSelLabel, "%.*s", i, z);
+ }
+ }
+#endif /* SELECTRACE_ENABLED */
}
oneselect(A) ::= values(X). {A = X;}
diff --git a/src/select.c b/src/select.c
index d3ffaf4..a0f6f35 100644
--- a/src/select.c
+++ b/src/select.c
@@ -15,6 +15,17 @@
#include "sqliteInt.h"
/*
+** Trace output macros
+*/
+#if SELECTTRACE_ENABLED
+/***/ int sqlite3SelectTrace = 0;
+# define SELECTTRACE(K,X) if(sqlite3SelectTrace&(K)) sqlite3DebugPrintf X
+#else
+# define SELECTTRACE(K,X)
+#endif
+
+
+/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
@@ -3355,6 +3366,8 @@
}
/***** If we reach this point, flattening is permitted. *****/
+ SELECTTRACE(1, ("flatten %s (term %d) into %s\n",
+ pSub->zSelLabel, iFrom, p->zSelLabel));
/* Authorize the subquery */
pParse->zAuthContext = pSubitem->zName;
diff --git a/src/shell.c b/src/shell.c
index ec83b13..9745e0f 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -3101,6 +3101,15 @@
}
}else
+
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+ if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
+ extern int sqlite3SelectTrace;
+ sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
+ }else
+#endif
+
+
#ifdef SQLITE_DEBUG
/* Undocumented commands for internal testing. Subject to change
** without notice. */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 75cfeef..2d63228 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -707,6 +707,17 @@
#endif
/*
+** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
+** the Select query generator tracing logic is turned on.
+*/
+#if defined(SQLITE_DEBUG) \
+ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE))
+# define SELECTTRACE_ENABLED 1
+#else
+# define SELECTTRACE_ENABLED 0
+#endif
+
+/*
** An instance of the following structure is used to store the busy-handler
** callback for a given sqlite handle.
**
@@ -2300,6 +2311,9 @@
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
+#if SELECTTRACE_ENABLED
+ char zSelLabel[12]; /* Text in comment following SELECT keyword */
+#endif
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
u64 nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
@@ -2558,6 +2572,9 @@
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
+#if SELECTTRACE_ENABLED
+ int nSelect; /* Number of SELECT statements seen */
+#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */