/*
** Generate a human-readable explanation of an expression tree.
*/
-void sqlite3ExplainExpr(Vdbe *pOut, Expr *p){
- if( p==0 ){
- sqlite3ExplainPrintf(pOut, "(C-null)");
- return;
- }
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- sqlite3ExplainPrintf(pOut, "(%s", p->u.zToken);
+void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
+ int op; /* The opcode being coded */
+ const char *zBinOp = 0; /* Binary operator */
+ const char *zUniOp = 0; /* Unary operator */
+ if( pExpr==0 ){
+ op = TK_NULL;
}else{
- sqlite3ExplainPrintf(pOut, "(op=%d", p->op);
+ op = pExpr->op;
}
- if( p->pLeft ){
- sqlite3ExplainPrintf(pOut, " left=");
- sqlite3ExplainExpr(pOut, p->pLeft);
+ switch( op ){
+ case TK_AGG_COLUMN: {
+ sqlite3ExplainPrintf(pOut, "AGG_COLUMN(%s:%d:%d)",
+ pExpr->pTab->zName, pExpr->iTable, pExpr->iColumn);
+ break;
+ }
+ case TK_COLUMN: {
+ if( pExpr->iTable<0 ){
+ /* This only happens when coding check constraints */
+ sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn);
+ }else{
+ sqlite3ExplainPrintf(pOut, "COLUMN(%s:%d:%d)",
+ pExpr->pTab->zName, pExpr->iTable, pExpr->iColumn);
+ }
+ break;
+ }
+ case TK_INTEGER: {
+ if( pExpr->flags & EP_IntValue ){
+ sqlite3ExplainPrintf(pOut, "INTEGER(%d)", pExpr->u.iValue);
+ }else{
+ sqlite3ExplainPrintf(pOut, "INTEGER(%s)", pExpr->u.zToken);
+ }
+ break;
+ }
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ case TK_FLOAT: {
+ sqlite3ExplainPrintf(pOut,"REAL(%s)", pExpr->u.zToken);
+ break;
+ }
+#endif
+ case TK_STRING: {
+ sqlite3ExplainPrintf(pOut,"STRING(%s)", pExpr->u.zToken);
+ break;
+ }
+ case TK_NULL: {
+ sqlite3ExplainPrintf(pOut,"NULL");
+ break;
+ }
+#ifndef SQLITE_OMIT_BLOB_LITERAL
+ case TK_BLOB: {
+ int n;
+ const char *z;
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
+ assert( pExpr->u.zToken[1]=='\'' );
+ z = &pExpr->u.zToken[2];
+ n = sqlite3Strlen30(z) - 1;
+ assert( z[n]=='\'' );
+ sqlite3ExplainPrintf(pOut,"BLOB(%.*s)", n, z);
+ break;
+ }
+#endif
+ case TK_VARIABLE: {
+ sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)",
+ pExpr->u.zToken, pExpr->iColumn);
+ break;
+ }
+ case TK_REGISTER: {
+ sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable);
+ break;
+ }
+ case TK_AS: {
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ break;
+ }
+#ifndef SQLITE_OMIT_CAST
+ case TK_CAST: {
+ /* Expressions of the form: CAST(pLeft AS token) */
+ const char *zAff = "unk";
+ switch( sqlite3AffinityType(pExpr->u.zToken) ){
+ case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
+ case SQLITE_AFF_NONE: zAff = "NONE"; break;
+ case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
+ case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
+ case SQLITE_AFF_REAL: zAff = "REAL"; break;
+ }
+ sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff);
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+#endif /* SQLITE_OMIT_CAST */
+ case TK_LT: zBinOp = "LT"; break;
+ case TK_LE: zBinOp = "LE"; break;
+ case TK_GT: zBinOp = "GT"; break;
+ case TK_GE: zBinOp = "GE"; break;
+ case TK_NE: zBinOp = "NE"; break;
+ case TK_EQ: zBinOp = "EQ"; break;
+ case TK_IS: zBinOp = "IS"; break;
+ case TK_ISNOT: zBinOp = "ISNOT"; break;
+ case TK_AND: zBinOp = "AND"; break;
+ case TK_OR: zBinOp = "OR"; break;
+ case TK_PLUS: zBinOp = "ADD"; break;
+ case TK_STAR: zBinOp = "MUL"; break;
+ case TK_MINUS: zBinOp = "SUB"; break;
+ case TK_REM: zBinOp = "REM"; break;
+ case TK_BITAND: zBinOp = "BITAND"; break;
+ case TK_BITOR: zBinOp = "BITOR"; break;
+ case TK_SLASH: zBinOp = "DIV"; break;
+ case TK_LSHIFT: zBinOp = "LSHIFT"; break;
+ case TK_RSHIFT: zBinOp = "RSHIFT"; break;
+ case TK_CONCAT: zBinOp = "CONCAT"; break;
+
+ case TK_UMINUS: zUniOp = "UMINUS"; break;
+ case TK_UPLUS: zUniOp = "UPLUS"; break;
+ case TK_BITNOT: zUniOp = "BITNOT"; break;
+ case TK_NOT: zUniOp = "NOT"; break;
+ case TK_ISNULL: zUniOp = "ISNULL"; break;
+ case TK_NOTNULL: zUniOp = "NOTNULL"; break;
+
+ case TK_AGG_FUNCTION:
+ case TK_CONST_FUNC:
+ case TK_FUNCTION: {
+ ExprList *pFarg; /* List of function arguments */
+ if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
+ pFarg = 0;
+ }else{
+ pFarg = pExpr->x.pList;
+ }
+ sqlite3ExplainPrintf(pOut, "%sFUNCTION:%s(",
+ op==TK_AGG_FUNCTION ? "AGG_" : "",
+ pExpr->u.zToken);
+ if( pFarg ){
+ sqlite3ExplainExprList(pOut, pFarg);
+ }
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+#ifndef SQLITE_OMIT_SUBQUERY
+ case TK_EXISTS: {
+ sqlite3ExplainPrintf(pOut, "EXISTS(");
+ sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ sqlite3ExplainPrintf(pOut,")");
+ break;
+ }
+ case TK_SELECT: {
+ sqlite3ExplainPrintf(pOut, "(");
+ sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+ case TK_IN: {
+ sqlite3ExplainPrintf(pOut, "IN(");
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut, ",");
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
+ }else{
+ sqlite3ExplainExprList(pOut, pExpr->x.pList);
+ }
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+#endif /* SQLITE_OMIT_SUBQUERY */
+
+ /*
+ ** x BETWEEN y AND z
+ **
+ ** This is equivalent to
+ **
+ ** x>=y AND x<=z
+ **
+ ** X is stored in pExpr->pLeft.
+ ** Y is stored in pExpr->pList->a[0].pExpr.
+ ** Z is stored in pExpr->pList->a[1].pExpr.
+ */
+ case TK_BETWEEN: {
+ Expr *pX = pExpr->pLeft;
+ Expr *pY = pExpr->x.pList->a[0].pExpr;
+ Expr *pZ = pExpr->x.pList->a[1].pExpr;
+ sqlite3ExplainPrintf(pOut, "BETWEEN(");
+ sqlite3ExplainExpr(pOut, pX);
+ sqlite3ExplainPrintf(pOut, ",");
+ sqlite3ExplainExpr(pOut, pY);
+ sqlite3ExplainPrintf(pOut, ",");
+ sqlite3ExplainExpr(pOut, pZ);
+ sqlite3ExplainPrintf(pOut, ")");
+ break;
+ }
+ case TK_TRIGGER: {
+ /* If the opcode is TK_TRIGGER, then the expression is a reference
+ ** to a column in the new.* or old.* pseudo-tables available to
+ ** trigger programs. In this case Expr.iTable is set to 1 for the
+ ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
+ ** is set to the column of the pseudo-table to read, or to -1 to
+ ** read the rowid field.
+ */
+ sqlite3ExplainPrintf(pOut, "%s(%d)",
+ pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
+ break;
+ }
+ case TK_CASE: {
+ sqlite3ExplainPrintf(pOut, "CASE(");
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut, ",");
+ sqlite3ExplainExprList(pOut, pExpr->x.pList);
+ break;
+ }
+#ifndef SQLITE_OMIT_TRIGGER
+ case TK_RAISE: {
+ const char *zType = "unk";
+ switch( pExpr->affinity ){
+ case OE_Rollback: zType = "rollback"; break;
+ case OE_Abort: zType = "abort"; break;
+ case OE_Fail: zType = "fail"; break;
+ case OE_Ignore: zType = "ignore"; break;
+ }
+ sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken);
+ break;
+ }
+#endif
}
- if( p->pRight ){
- sqlite3ExplainPrintf(pOut, " right=");
- sqlite3ExplainExpr(pOut, p->pRight);
+ if( zBinOp ){
+ sqlite3ExplainPrintf(pOut,"%s(", zBinOp);
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut,",");
+ sqlite3ExplainExpr(pOut, pExpr->pRight);
+ sqlite3ExplainPrintf(pOut,")");
+ }else if( zUniOp ){
+ sqlite3ExplainPrintf(pOut,"%s(", zUniOp);
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut,")");
}
- sqlite3ExplainPrintf(pOut, ")");
}
#endif /* defined(SQLITE_DEBUG) */
*/
void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
int i;
- if( pList==0 ){
+ if( pList==0 || pList->nExpr==0 ){
sqlite3ExplainPrintf(pOut, "(empty-list)");
return;
- }
- sqlite3ExplainPush(pOut);
- for(i=0; i<pList->nExpr; i++){
- sqlite3ExplainPrintf(pOut, "%02d: ", i);
+ }else if( pList->nExpr==1 ){
+ sqlite3ExplainExpr(pOut, pList->a[0].pExpr);
+ }else{
sqlite3ExplainPush(pOut);
- sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
- sqlite3ExplainPop(pOut);
- if( i<pList->nExpr-1 ){
- sqlite3ExplainNL(pOut);
+ for(i=0; i<pList->nExpr; i++){
+ sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
+ sqlite3ExplainPush(pOut);
+ sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
+ sqlite3ExplainPop(pOut);
+ if( i<pList->nExpr-1 ){
+ sqlite3ExplainNL(pOut);
+ }
}
+ sqlite3ExplainPop(pOut);
}
- sqlite3ExplainPop(pOut);
}
#endif /* SQLITE_DEBUG */
/*
** Generate a human-readable description of a the Select object.
*/
-void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
- if( p==0 ){
- sqlite3ExplainPrintf(pVdbe, "(empty-select)");
- return;
- }
+static void explainOneSelect(Vdbe *pVdbe, Select *p){
sqlite3ExplainPrintf(pVdbe, "SELECT ");
- sqlite3ExplainPush(pVdbe);
sqlite3ExplainExprList(pVdbe, p->pEList);
sqlite3ExplainNL(pVdbe);
- sqlite3ExplainPop(pVdbe);
if( p->pSrc && p->pSrc->nSrc ){
int i;
- sqlite3ExplainPrintf(pVdbe, " FROM ");
+ sqlite3ExplainPrintf(pVdbe, "FROM ");
sqlite3ExplainPush(pVdbe);
for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i];
- sqlite3ExplainPrintf(pVdbe, "%02d: ", i);
- sqlite3ExplainPush(pVdbe);
+ sqlite3ExplainPrintf(pVdbe, "src[%d] = ", i);
if( pItem->pSelect ){
sqlite3ExplainSelect(pVdbe, pItem->pSelect);
}else if( pItem->zName ){
sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName);
}
if( pItem->pTab ){
- sqlite3ExplainPrintf(pVdbe, " (table: %s)", pItem->pTab->zName);
+ sqlite3ExplainPrintf(pVdbe, " (name=%s:%d)",
+ pItem->pTab->zName, pItem->iCursor);
+ }
+ if( pItem->jointype & JT_LEFT ){
+ sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN");
}
if( pItem->zAlias ){
sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias);
}
sqlite3ExplainNL(pVdbe);
- sqlite3ExplainPop(pVdbe);
}
sqlite3ExplainPop(pVdbe);
}
if( p->pWhere ){
- sqlite3ExplainPrintf(pVdbe, " WHERE ");
+ sqlite3ExplainPrintf(pVdbe, "WHERE ");
sqlite3ExplainExpr(pVdbe, p->pWhere);
sqlite3ExplainNL(pVdbe);
}
if( p->pGroupBy ){
- sqlite3ExplainPrintf(pVdbe, " GROUP BY ");
+ sqlite3ExplainPrintf(pVdbe, "GROUPBY ");
sqlite3ExplainExprList(pVdbe, p->pGroupBy);
sqlite3ExplainNL(pVdbe);
}
sqlite3ExplainNL(pVdbe);
}
if( p->pOrderBy ){
- sqlite3ExplainPrintf(pVdbe, " ORDER BY ");
+ sqlite3ExplainPrintf(pVdbe, "ORDERBY ");
sqlite3ExplainExprList(pVdbe, p->pOrderBy);
sqlite3ExplainNL(pVdbe);
}
- sqlite3ExplainPrintf(pVdbe, " END");
+ if( p->pLimit ){
+ sqlite3ExplainPrintf(pVdbe, "LIMIT ");
+ sqlite3ExplainExpr(pVdbe, p->pLimit);
+ sqlite3ExplainNL(pVdbe);
+ }
+ if( p->pOffset ){
+ sqlite3ExplainPrintf(pVdbe, "OFFSET ");
+ sqlite3ExplainExpr(pVdbe, p->pOffset);
+ sqlite3ExplainNL(pVdbe);
+ }
+}
+void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
+ if( p==0 ){
+ sqlite3ExplainPrintf(pVdbe, "(null-select)");
+ return;
+ }
+ while( p->pPrior ) p = p->pPrior;
+ sqlite3ExplainPush(pVdbe);
+ while( p ){
+ explainOneSelect(pVdbe, p);
+ p = p->pNext;
+ if( p==0 ) break;
+ sqlite3ExplainNL(pVdbe);
+ sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op));
+ }
+ sqlite3ExplainPrintf(pVdbe, "END");
+ sqlite3ExplainPop(pVdbe);
}
/* End of the structure debug printing code