]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Improvements to the data-structure explain subsystem. Most queries now
authordrh <drh@noemail.net>
Wed, 7 Dec 2011 01:23:51 +0000 (01:23 +0000)
committerdrh <drh@noemail.net>
Wed, 7 Dec 2011 01:23:51 +0000 (01:23 +0000)
give a reasonably detailed graph of their parse tree.

FossilOrigin-Name: 0aa7d3d2346bdddcc4e1e25ee26d13c8594885e5

manifest
manifest.uuid
src/expr.c
src/select.c

index a93f5c0b29b2879cd5bf3ca6f6e2749b33266521..e924999ec2b9cdd948204b9cbd24be0cd09a3c57 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Begin\sadding\sthe\sdata-structure\sexplaining\ssubsystem.\s\sAll\sis\scontained\swithin
-D 2011-12-06T19:44:51.212
+C Improvements\sto\sthe\sdata-structure\sexplain\ssubsystem.\s\sMost\squeries\snow\ngive\sa\sreasonably\sdetailed\sgraph\sof\stheir\sparse\stree.
+D 2011-12-07T01:23:51.800
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -134,7 +134,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
 F src/delete.c 51d32f0a9c880663e54ce309f52e40c325d5e112
-F src/expr.c 942171222a30af8cf4f9504a43ef6cadaf993dae
+F src/expr.c 62f6ad2a1dcfbf684e6916c0662d5b4f28b98346
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
 F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9
@@ -180,7 +180,7 @@ F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
 F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 2923f3129afcddb8023971ab591b07cdc868c163
+F src/select.c 352ac58d6070f9a5564e9648bc2202b9d6339747
 F src/shell.c a1eadb2fdbfa45e54307263f0c8da8ee8cd61b8b
 F src/sqlite.h.in 1dc07194eb1a2c69c8ef75f88022b170be08024a
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
@@ -977,7 +977,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P 162421dadf93e9201c3290d800c597cbeeacdb40
-R ddbfe0a87d25503aebbe5e810f678862
+P 79ae51c5b1b20ed0a425a87e65a32a096a80b7e1
+R 33f29d39c143746ce94119c4aaec65fd
 U drh
-Z ed29fdae1618daadbff0e860a54f25e4
+Z 8a3e65c823a12538f790d9d174308040
index 12034d7e1af682270c79be6a8b11f7d07bffbfbc..dbbd00345888933f370844ee636709f09a547e6e 100644 (file)
@@ -1 +1 @@
-79ae51c5b1b20ed0a425a87e65a32a096a80b7e1
\ No newline at end of file
+0aa7d3d2346bdddcc4e1e25ee26d13c8594885e5
\ No newline at end of file
index d157743ab0403babfc8ad303fb28549502409455..0d217ed405f1c737b8b67248bdb277a20435e90e 100644 (file)
@@ -2943,25 +2943,238 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
 /*
 ** 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) */
 
@@ -2971,21 +3184,24 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *p){
 */
 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 */
 
index 75b6a60e0550813c379d0d28db57bb443d538fb4..539e4156a1cf95f6762b5d870591160311c82a13 100644 (file)
@@ -4498,47 +4498,43 @@ select_end:
 /*
 ** 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);
   }
@@ -4548,11 +4544,37 @@ void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
     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