If anyone is interested, the attached code patch can dump an 
internal parse tree of an SQLite SELECT statement.
Perhaps it may be of use to someone doing SQL statement analysis,
transformations or SQL source-level optimizations.

An example:

sqlite> select * from (select Type, Name from (select name, type from 
sqlite_master union all
select 123 TYPE, 456 NAME));

sqlite3SelectDump Parse=0x22e6d0, Select=0x56eb30
Select 0x56eb30: {
  op: TK_SELECT
  pEList: {
    a[0]: {
      zName: Type
      pExpr: {
        op: TK_COLUMN
        token: {Type}
        span: {Type}
        affinity: SQLITE_AFF_TEXT
        iTable: 0
        iColumn: 0
      }
    }
    a[1]: {
      zName: Name
      pExpr: {
        op: TK_COLUMN
        token: {Name}
        span: {Name}
        affinity: SQLITE_AFF_TEXT
        iTable: 0
        iColumn: 1
      }
    }
  }
  pSrc: {
    a[0]: {
      zAlias: sqlite_subquery_56EAB8_
      iCursor: 0
      colUsed: 0x00000003
      pTab: sqlite_subquery_56EAB8_
      pSelect: {
        op: TK_SELECT
        pEList: {
          a[0]: {
            pExpr: {
              op: TK_COLUMN
              token: {Type}
              span: {Type}
              affinity: SQLITE_AFF_TEXT
              iTable: 1
              iColumn: 1
            }
          }
          a[1]: {
            pExpr: {
              op: TK_COLUMN
              token: {Name}
              span: {Name}
              affinity: SQLITE_AFF_TEXT
              iTable: 1
              iColumn: 0
            }
          }
        }
        pSrc: {
          a[0]: {
            zAlias: sqlite_subquery_56EA40_
            iCursor: 1
            colUsed: 0x00000003
            pTab: sqlite_subquery_56EA40_
            pSelect: {
              op: TK_ALL
              pEList: {
                a[0]: {
                  zName: TYPE
                  pExpr: {
                    op: TK_INTEGER
                    token: {123}
                    span: {123}
                  }
                }
                a[1]: {
                  zName: NAME
                  pExpr: {
                    op: TK_INTEGER
                    token: {456}
                    span: {456}
                  }
                }
              }
              pPrior: {
                op: TK_SELECT
                pEList: {
                  a[0]: {
                    pExpr: {
                      op: TK_COLUMN
                      token: {name}
                      span: {name}
                      affinity: SQLITE_AFF_TEXT
                      iTable: 2
                      iColumn: 1
                      pTab: sqlite_master
                    }
                  }
                  a[1]: {
                    pExpr: {
                      op: TK_COLUMN
                      token: {type}
                      span: {type}
                      affinity: SQLITE_AFF_TEXT
                      iTable: 2
                      iColumn: 0
                      pTab: sqlite_master
                    }
                  }
                }
                pSrc: {
                  a[0]: {
                    zName: sqlite_master
                    iCursor: 2
                    colUsed: 0x00000003
                    pTab: sqlite_master
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Select tree after successful flattenSubquery():

sqlite3SelectDump Parse=0x0, Select=0x56eb30
Select 0x56eb30: {
  op: TK_SELECT
  pEList: {
    a[0]: {
      zName: Type
      pExpr: {
        op: TK_COLUMN
        token: {Type}
        span: {Type}
        affinity: SQLITE_AFF_TEXT
        iTable: 1
        iColumn: 1
      }
    }
    a[1]: {
      zName: Name
      pExpr: {
        op: TK_COLUMN
        token: {Name}
        span: {Name}
        affinity: SQLITE_AFF_TEXT
        iTable: 1
        iColumn: 0
      }
    }
  }
  pSrc: {
    a[0]: {
      zAlias: sqlite_subquery_56EA40_
      iCursor: 1
      colUsed: 0x00000003
      pTab: sqlite_subquery_56EA40_
      pSelect: {
        op: TK_ALL
        pEList: {
          a[0]: {
            zName: TYPE
            pExpr: {
              op: TK_INTEGER
              token: {123}
              span: {123}
            }
          }
          a[1]: {
            zName: NAME
            pExpr: {
              op: TK_INTEGER
              token: {456}
              span: {456}
            }
          }
        }
        pPrior: {
          op: TK_SELECT
          pEList: {
            a[0]: {
              pExpr: {
                op: TK_COLUMN
                token: {name}
                span: {name}
                affinity: SQLITE_AFF_TEXT
                iTable: 2
                iColumn: 1
                pTab: sqlite_master
              }
            }
            a[1]: {
              pExpr: {
                op: TK_COLUMN
                token: {type}
                span: {type}
                affinity: SQLITE_AFF_TEXT
                iTable: 2
                iColumn: 0
                pTab: sqlite_master
              }
            }
          }
          pSrc: {
            a[0]: {
              zName: sqlite_master
              iCursor: 2
              colUsed: 0x00000003
              pTab: sqlite_master
            }
          }
          pRightmost: 0x56ea40
        }
        pRightmost: 0x56ea40
      }
    }
  }
}
456|123


Be aware that SQLite merges its code generation phase with 
its various transformations (such as sub-select flattening).
As result, you may not be looking at the actual parse tree 
SQLite ends up with just prior to its VDBE code generation.


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 
Index: src/parse.y
===================================================================
RCS file: /sqlite/sqlite/src/parse.y,v
retrieving revision 1.206
diff -u -3 -p -r1.206 parse.y
--- src/parse.y 11 Jul 2006 10:42:36 -0000      1.206
+++ src/parse.y 24 Jul 2006 03:15:53 -0000
@@ -366,6 +366,7 @@ cmd ::= DROP VIEW ifexists(E) fullname(X
 //////////////////////// The SELECT statement /////////////////////////////////
 //
 cmd ::= select(X).  {
+  sqlite3SelectDump(pParse, X);
   sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
   sqlite3SelectDelete(X);
 }
Index: src/select.c
===================================================================
RCS file: /sqlite/sqlite/src/select.c,v
retrieving revision 1.319
diff -u -3 -p -r1.319 select.c
--- src/select.c        11 Jul 2006 13:15:08 -0000      1.319
+++ src/select.c        24 Jul 2006 03:15:54 -0000
@@ -17,6 +17,545 @@
 #include "sqliteInt.h"
 
 
+static int g_printNULLs = 0; /* set to 1 for more verbose output */
+
+static const char g_Indent[] = "                                            "
+ "                                                                          "
+ "                                                                          "
+ "                                                                          ";
+#define g_Indent_length (sizeof(g_Indent)/sizeof(g_Indent[0]))
+
+static void dumpSelect(Parse*, int level, const char* name, Select* p);
+static void dumpExpr(Parse*, int level, const char* name, Expr* p);
+static void dumpExprList(Parse*, int level, const char* name, ExprList* p);
+
+static const char* indent(int level) {
+  if (level <= 0) return "";
+  if (level > 100) { printf("\nfatal\n"); exit(1); }
+  return g_Indent + (g_Indent_length-1) - level*2;
+}
+
+static void
+dumpInt(Parse* pParse, int level, const char* name, int value) {
+  printf("%s%s: %d\n", indent(level), name, value);
+}
+
+static const char* op2str(int op) {
+    switch (op) {
+    case TK_SEMI: return "TK_SEMI";
+    case TK_EXPLAIN: return "TK_EXPLAIN";
+    case TK_QUERY: return "TK_QUERY";
+    case TK_PLAN: return "TK_PLAN";
+    case TK_BEGIN: return "TK_BEGIN";
+    case TK_TRANSACTION: return "TK_TRANSACTION";
+    case TK_DEFERRED: return "TK_DEFERRED";
+    case TK_IMMEDIATE: return "TK_IMMEDIATE";
+    case TK_EXCLUSIVE: return "TK_EXCLUSIVE";
+    case TK_COMMIT: return "TK_COMMIT";
+    case TK_END: return "TK_END";
+    case TK_ROLLBACK: return "TK_ROLLBACK";
+    case TK_CREATE: return "TK_CREATE";
+    case TK_TABLE: return "TK_TABLE";
+    case TK_IF: return "TK_IF";
+    case TK_NOT: return "TK_NOT";
+    case TK_EXISTS: return "TK_EXISTS";
+    case TK_TEMP: return "TK_TEMP";
+    case TK_LP: return "TK_LP";
+    case TK_RP: return "TK_RP";
+    case TK_AS: return "TK_AS";
+    case TK_COMMA: return "TK_COMMA";
+    case TK_ID: return "TK_ID";
+    case TK_ABORT: return "TK_ABORT";
+    case TK_AFTER: return "TK_AFTER";
+    case TK_ANALYZE: return "TK_ANALYZE";
+    case TK_ASC: return "TK_ASC";
+    case TK_ATTACH: return "TK_ATTACH";
+    case TK_BEFORE: return "TK_BEFORE";
+    case TK_CASCADE: return "TK_CASCADE";
+    case TK_CAST: return "TK_CAST";
+    case TK_CONFLICT: return "TK_CONFLICT";
+    case TK_DATABASE: return "TK_DATABASE";
+    case TK_DESC: return "TK_DESC";
+    case TK_DETACH: return "TK_DETACH";
+    case TK_EACH: return "TK_EACH";
+    case TK_FAIL: return "TK_FAIL";
+    case TK_FOR: return "TK_FOR";
+    case TK_IGNORE: return "TK_IGNORE";
+    case TK_INITIALLY: return "TK_INITIALLY";
+    case TK_INSTEAD: return "TK_INSTEAD";
+    case TK_LIKE_KW: return "TK_LIKE_KW";
+    case TK_MATCH: return "TK_MATCH";
+    case TK_KEY: return "TK_KEY";
+    case TK_OF: return "TK_OF";
+    case TK_OFFSET: return "TK_OFFSET";
+    case TK_PRAGMA: return "TK_PRAGMA";
+    case TK_RAISE: return "TK_RAISE";
+    case TK_REPLACE: return "TK_REPLACE";
+    case TK_RESTRICT: return "TK_RESTRICT";
+    case TK_ROW: return "TK_ROW";
+    case TK_STATEMENT: return "TK_STATEMENT";
+    case TK_TRIGGER: return "TK_TRIGGER";
+    case TK_VACUUM: return "TK_VACUUM";
+    case TK_VIEW: return "TK_VIEW";
+    case TK_VIRTUAL: return "TK_VIRTUAL";
+    case TK_REINDEX: return "TK_REINDEX";
+    case TK_RENAME: return "TK_RENAME";
+    case TK_CTIME_KW: return "TK_CTIME_KW";
+    case TK_ANY: return "TK_ANY";
+    case TK_OR: return "TK_OR";
+    case TK_AND: return "TK_AND";
+    case TK_IS: return "TK_IS";
+    case TK_BETWEEN: return "TK_BETWEEN";
+    case TK_IN: return "TK_IN";
+    case TK_ISNULL: return "TK_ISNULL";
+    case TK_NOTNULL: return "TK_NOTNULL";
+    case TK_NE: return "TK_NE";
+    case TK_EQ: return "TK_EQ";
+    case TK_GT: return "TK_GT";
+    case TK_LE: return "TK_LE";
+    case TK_LT: return "TK_LT";
+    case TK_GE: return "TK_GE";
+    case TK_ESCAPE: return "TK_ESCAPE";
+    case TK_BITAND: return "TK_BITAND";
+    case TK_BITOR: return "TK_BITOR";
+    case TK_LSHIFT: return "TK_LSHIFT";
+    case TK_RSHIFT: return "TK_RSHIFT";
+    case TK_PLUS: return "TK_PLUS";
+    case TK_MINUS: return "TK_MINUS";
+    case TK_STAR: return "TK_STAR";
+    case TK_SLASH: return "TK_SLASH";
+    case TK_REM: return "TK_REM";
+    case TK_CONCAT: return "TK_CONCAT";
+    case TK_UMINUS: return "TK_UMINUS";
+    case TK_UPLUS: return "TK_UPLUS";
+    case TK_BITNOT: return "TK_BITNOT";
+    case TK_STRING: return "TK_STRING";
+    case TK_JOIN_KW: return "TK_JOIN_KW";
+    case TK_CONSTRAINT: return "TK_CONSTRAINT";
+    case TK_DEFAULT: return "TK_DEFAULT";
+    case TK_NULL: return "TK_NULL";
+    case TK_PRIMARY: return "TK_PRIMARY";
+    case TK_UNIQUE: return "TK_UNIQUE";
+    case TK_CHECK: return "TK_CHECK";
+    case TK_REFERENCES: return "TK_REFERENCES";
+    case TK_COLLATE: return "TK_COLLATE";
+    case TK_AUTOINCR: return "TK_AUTOINCR";
+    case TK_ON: return "TK_ON";
+    case TK_DELETE: return "TK_DELETE";
+    case TK_UPDATE: return "TK_UPDATE";
+    case TK_INSERT: return "TK_INSERT";
+    case TK_SET: return "TK_SET";
+    case TK_DEFERRABLE: return "TK_DEFERRABLE";
+    case TK_FOREIGN: return "TK_FOREIGN";
+    case TK_DROP: return "TK_DROP";
+    case TK_UNION: return "TK_UNION";
+    case TK_ALL: return "TK_ALL";
+    case TK_EXCEPT: return "TK_EXCEPT";
+    case TK_INTERSECT: return "TK_INTERSECT";
+    case TK_SELECT: return "TK_SELECT";
+    case TK_DISTINCT: return "TK_DISTINCT";
+    case TK_DOT: return "TK_DOT";
+    case TK_FROM: return "TK_FROM";
+    case TK_JOIN: return "TK_JOIN";
+    case TK_USING: return "TK_USING";
+    case TK_ORDER: return "TK_ORDER";
+    case TK_BY: return "TK_BY";
+    case TK_GROUP: return "TK_GROUP";
+    case TK_HAVING: return "TK_HAVING";
+    case TK_LIMIT: return "TK_LIMIT";
+    case TK_WHERE: return "TK_WHERE";
+    case TK_INTO: return "TK_INTO";
+    case TK_VALUES: return "TK_VALUES";
+    case TK_INTEGER: return "TK_INTEGER";
+    case TK_FLOAT: return "TK_FLOAT";
+    case TK_BLOB: return "TK_BLOB";
+    case TK_REGISTER: return "TK_REGISTER";
+    case TK_VARIABLE: return "TK_VARIABLE";
+    case TK_CASE: return "TK_CASE";
+    case TK_WHEN: return "TK_WHEN";
+    case TK_THEN: return "TK_THEN";
+    case TK_ELSE: return "TK_ELSE";
+    case TK_INDEX: return "TK_INDEX";
+    case TK_ALTER: return "TK_ALTER";
+    case TK_TO: return "TK_TO";
+    case TK_ADD: return "TK_ADD";
+    case TK_COLUMNKW: return "TK_COLUMNKW";
+    case TK_TO_TEXT: return "TK_TO_TEXT";
+    case TK_TO_BLOB: return "TK_TO_BLOB";
+    case TK_TO_NUMERIC: return "TK_TO_NUMERIC";
+    case TK_TO_INT: return "TK_TO_INT";
+    case TK_TO_REAL: return "TK_TO_REAL";
+    case TK_END_OF_FILE: return "TK_END_OF_FILE";
+    case TK_ILLEGAL: return "TK_ILLEGAL";
+    case TK_SPACE: return "TK_SPACE";
+    case TK_UNCLOSED_STRING: return "TK_UNCLOSED_STRING";
+    case TK_COMMENT: return "TK_COMMENT";
+    case TK_FUNCTION: return "TK_FUNCTION";
+    case TK_COLUMN: return "TK_COLUMN";
+    case TK_AGG_FUNCTION: return "TK_AGG_FUNCTION";
+    case TK_AGG_COLUMN: return "TK_AGG_COLUMN";
+    case TK_CONST_FUNC: return "TK_CONST_FUNC";
+    }
+    return "unknown op";
+}
+
+static void
+dumpOp(Parse* pParse, int level, const char* name, int op) {
+  printf("%s%s: %s\n", indent(level), name, op2str(op));
+}
+
+static void
+dumpUnsigned(Parse* pParse, int level, const char* name, unsigned value) {
+  printf("%s%s: %u\n", indent(level), name, value);
+}
+
+static void
+dumpFlag(Parse* pParse, int level, const char* name, unsigned value) {
+  if (g_printNULLs && value)
+    printf("%s%s: %u\n", indent(level), name, value);
+}
+
+static void
+dumpString(Parse* pParse, int level, const char* name, const char* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: %s\n", indent(level), name, p);
+}
+
+static void
+dumpPointer(Parse* pParse, int level, const char* name, void* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: %p\n", indent(level), name, p);
+}
+
+static void
+dumpChar(Parse* pParse, int level, const char* name, char p) {
+  if (!p) {
+    printf("%s%s: NIL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: %c\n", indent(level), name, p);
+}
+
+static const char* GetAffinityString(char aff) {
+  switch (aff) {
+  case SQLITE_AFF_TEXT: return "SQLITE_AFF_TEXT";
+  case SQLITE_AFF_NONE: return "SQLITE_AFF_NONE";
+  case SQLITE_AFF_NUMERIC: return "SQLITE_AFF_NUMERIC";
+  case SQLITE_AFF_INTEGER: return "SQLITE_AFF_INTEGER";
+  case SQLITE_AFF_REAL: return "SQLITE_AFF_REAL";
+  }
+  return "NULL";
+}
+
+static void
+dumpAffinity(Parse* pParse, int level, const char* name, char p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NIL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: %s\n", indent(level), name, GetAffinityString(p));
+}
+
+static void
+dumpExprFlags(Parse* pParse, int level, const char* name, unsigned value) {
+  char buf[512];
+  if (value == EP_Resolved) return;
+  buf[0] = 0;
+  if (value & EP_FromJoin)  { strcat(buf, "EP_FromJoin "); }
+  if (value & EP_Agg)       { strcat(buf, "EP_Agg "); }
+  if (value & EP_Resolved)  { strcat(buf, "EP_Resolved "); }
+  if (value & EP_Error)     { strcat(buf, "EP_Error "); }
+  if (value & EP_Distinct)  { strcat(buf, "EP_Distinct "); }
+  if (value & EP_VarSelect) { strcat(buf, "EP_VarSelect "); }
+  if (value & EP_Dequoted)  { strcat(buf, "EP_Dequoted "); }
+  if (value & EP_InfixFunc) { strcat(buf, "EP_InfixFunc "); }
+  printf("%s%s: %s\n", indent(level), name, buf);
+}
+
+static void
+dumpToken(Parse* pParse, int level, const char* name, Token p) {
+  if (!p.z) {
+    /*if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);*/
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+#if 1
+  /* not verbose */
+  printf("%s%s: {%-.*s}\n", indent(level), name, p.n, p.z);
+#else
+  /* verbose */
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  dumpUnsigned(pParse, level, "n", p.n);
+  dumpFlag(pParse, level, "dyn", p.dyn);
+  printf("%sz: {%-.*s}\n", indent(level), p.n, p.z);
+  --level;
+  printf("%s}\n", indent(level));
+#endif
+}
+
+static void
+dumpTable(Parse* pParse, int level, const char* name, Table* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: %s\n", indent(level), name, p->zName);
+  ++level;
+  /*dumpString(pParse, level, "zName", p);*/
+}
+
+static const char* GetCollSeq(u8 type) {
+  switch (type) {
+  case SQLITE_COLL_BINARY: return "SQLITE_COLL_BINARY";
+  case SQLITE_COLL_NOCASE: return "SQLITE_COLL_NOCASE";
+  case SQLITE_COLL_REVERSE: return "SQLITE_COLL_REVERSE";
+  case SQLITE_COLL_USER: return "SQLITE_COLL_USER";
+  }
+  return "unknown";
+}
+
+static void
+dumpCollSeq(Parse* pParse, int level, const char* name, CollSeq* p) {
+  if (p && p->xCmp) {
+    /* BINARY is the typical case, so no need to print it always */
+    if (p->type == SQLITE_COLL_BINARY) return;
+
+    printf("%s%s: {\n", indent(level), name);
+    ++level;
+    dumpString(pParse, level, "zName", p->zName);
+    dumpUnsigned(pParse, level, "enc", p->enc);
+    dumpString(pParse, level, "type", GetCollSeq(p->type));
+    dumpPointer(pParse, level, "pUser", p->pUser);
+    dumpPointer(pParse, level, "xCmp", p->xCmp);
+    --level;
+    printf("%s}\n", indent(level));
+  }
+}
+
+static void
+dumpExpr(Parse* pParse, int level, const char* name, Expr* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: {\n", indent(level), name, p);
+  ++level;
+  dumpOp(pParse, level, "op", p->op);
+  dumpToken(pParse, level, "token", p->token);
+  dumpToken(pParse, level, "span", p->span);
+  dumpAffinity(pParse, level, "affinity", p->affinity);
+  dumpExprFlags(pParse, level, "flags", p->flags);
+  if (p->op == TK_COLUMN) dumpInt(pParse, level, "iTable",  p->iTable);
+  if (p->op == TK_COLUMN) dumpInt(pParse, level, "iColumn", p->iColumn);
+  dumpPointer(pParse, level, "pAggInfo", p->pAggInfo);
+  if (p->iAgg != -1) dumpInt(pParse, level, "iAgg", p->iAgg);
+  if (p->flags & EP_FromJoin)
+    dumpInt(pParse, level, "iRightJoinTable", p->iRightJoinTable);
+  dumpCollSeq(pParse, level, "pColl", p->pColl);
+  dumpExpr(pParse, level, "pLeft", p->pLeft);
+  dumpExpr(pParse, level, "pRight", p->pRight);
+  dumpExprList(pParse, level, "pList", p->pList);
+  dumpPointer(pParse, level, "pSelect", p->pSelect);
+  dumpTable(pParse, level, "pTab", p->pTab);
+  /* dumpPointer(pParse, level, "pSchema", p->pSchema); */
+  --level;
+  printf("%s}\n", indent(level));
+}
+
+static void
+dumpJointype(Parse* pParse, int level, const char* name, unsigned jointype) {
+  char buf[200];
+  if (!jointype) return;
+  buf[0] = 0;
+  if (jointype & JT_INNER)   { strcat(buf, "JT_INNER "); }
+  if (jointype & JT_CROSS)   { strcat(buf, "JT_CROSS "); }
+  if (jointype & JT_NATURAL) { strcat(buf, "JT_NATURAL "); }
+  if (jointype & JT_LEFT)    { strcat(buf, "JT_LEFT "); }
+  if (jointype & JT_RIGHT)   { strcat(buf, "JT_RIGHT "); }
+  if (jointype & JT_OUTER)   { strcat(buf, "JT_OUTER "); }
+  printf("%s%s: %s\n", indent(level), name, buf);
+}
+
+static void
+dumpIdList_item(Parse* pParse, int level, const char* name,
+                struct IdList_item* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  dumpString(pParse, level, "zName", p->zName);                             
+  /* dumpInt(pParse, level, "idx", p->idx); not used in SELECT */
+  --level;
+  printf("%s}\n", indent(level));
+}
+
+static void
+dumpIdList(Parse* pParse, int level, const char* name, IdList* p) {
+  int i;
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  if (p->nId <= 0) return;
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  /* dumpInt(pParse, level, "nAlloc", p->nAlloc); */
+  /* dumpInt(pParse, level, "nId", p->nId); */
+  for (i = 0; i < p->nId; ++i) {
+    char buf[100];
+    sprintf(buf, "a[%d]", i);
+    dumpIdList_item(pParse, level, buf, &p->a[i]);
+  }
+  --level;
+  printf("%s}\n", indent(level));
+}
+
+static void
+dumpHex(Parse* pParse, int level, const char* name, unsigned value) {
+  printf("%s%s: 0x%08x\n", indent(level), name, value);
+}
+
+static void
+dumpSrcList_item(Parse* pParse, int level, const char* name,
+                 struct SrcList_item* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  dumpString(pParse, level, "zDatabase", p->zDatabase);
+  dumpString(pParse, level, "zName", p->zName);
+  dumpString(pParse, level, "zAlias", p->zAlias);
+  dumpFlag(pParse, level, "isPopulated", p->isPopulated);
+  /* if (p->iCursor != -1) dumpInt(pParse, level, "iCursor", p->iCursor); */
+  dumpInt(pParse, level, "iCursor", p->iCursor);
+  if (p->colUsed) dumpHex(pParse, level, "colUsed", p->colUsed);
+  dumpTable(pParse, level, "pTab", p->pTab);
+  dumpSelect(pParse, level, "pSelect", p->pSelect);
+  dumpJointype(pParse, level, "jointype", p->jointype);
+  dumpExpr(pParse, level, "pOn", p->pOn);
+  dumpIdList(pParse, level, "pUsing", p->pUsing); /* converted to pWhere */
+  --level;
+  printf("%s}\n", indent(level));
+}
+
+static void
+dumpSrcList(Parse* pParse, int level, const char* name, SrcList* p) {
+  int i;
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  if (p->nSrc <= 0) return;
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  /* dumpInt(pParse, level, "nAlloc", p->nAlloc); */
+  /* dumpInt(pParse, level, "nSrc", p->nSrc); */
+  for (i = 0; i < p->nSrc; ++i) {
+    char buf[200];
+    sprintf(buf, "a[%d]", i);
+    dumpSrcList_item(pParse, level, buf, &p->a[i]);
+  }
+  --level;
+  printf("%s}\n", indent(level));
+}
+
+static void
+dumpSortOrder(Parse* pParse, int level, const char* name, unsigned value) {
+  if (g_printNULLs && value)
+    printf("%s%s: %s\n", indent(level), name, (value ? "DESC" : "ASC"));
+}
+
+static void
+dumpExprList_item(Parse* pParse, int level, const char* name,
+                  struct ExprList_item* p) {
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  dumpString(pParse, level, "zName", p->zName);
+  dumpSortOrder(pParse, level, "sortOrder", p->sortOrder);
+  dumpFlag(pParse, level, "isAgg", p->isAgg);
+  dumpFlag(pParse, level, "done", p->done);
+  dumpExpr(pParse, level, "pExpr", p->pExpr);
+  --level;
+  printf("%s%}\n", indent(level));
+}
+
+static void
+dumpExprList(Parse* pParse, int level, const char* name, ExprList* p) {
+  int i;
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  if (p->nExpr <= 0) return;
+  printf("%s%s: {\n", indent(level), name);
+  ++level;
+  /* dumpUnsigned(pParse, level, "iECursor", p->iECursor); */
+  /* dumpUnsigned(pParse, level, "nAlloc", p->nAlloc); */
+  /* dumpUnsigned(pParse, level, "nExpr", p->nExpr); */
+  for (i = 0; i < p->nExpr; ++i) {
+    char buf[200];
+    sprintf(buf, "a[%d]", i);
+    dumpExprList_item(pParse, level, buf, &p->a[i]);
+  }
+  --level;
+  printf("%s}\n", indent(level));
+}
+
+static void
+dumpSelect(Parse* pParse, int level, const char* name, Select* p) {
+  if (pParse && p && sqlite3SelectResolve(pParse, p, 0)){ return; }
+  if (!p) {
+    if (g_printNULLs) printf("%s%s: NULL\n", indent(level), name);
+    return;
+  }
+  printf("%s%s: {\n", indent(level), name);
+  level++;
+  dumpOp(pParse, level, "op", p->op);
+  dumpFlag(pParse, level, "isDistinct", p->isDistinct);
+  dumpFlag(pParse, level, "isResolved", p->isResolved);
+  dumpFlag(pParse, level, "isAgg", p->isAgg);
+  dumpFlag(pParse, level, "usesEphm", p->usesEphm);
+  dumpExprList(pParse, level, "pEList", p->pEList);
+  dumpFlag(pParse, level, "disallowOrderBy", p->disallowOrderBy);
+  dumpSrcList(pParse, level, "pSrc", p->pSrc);
+  dumpExpr(pParse, level, "pWhere", p->pWhere);
+  dumpExprList(pParse, level, "pGroupBy", p->pGroupBy);
+  dumpExpr(pParse, level, "pHaving", p->pHaving);
+  dumpExprList(pParse, level, "pOrderBy", p->pOrderBy);
+  dumpSelect(pParse, level, "pPrior", p->pPrior);
+  dumpPointer(pParse, level, "pRightmost", p->pRightmost);
+  dumpExpr(pParse, level, "pLimit", p->pLimit);
+  dumpExpr(pParse, level, "pOffset", p->pOffset);
+  if (p->iLimit != -1) dumpInt(pParse, level, "iLimit", p->iLimit);
+  if (p->iOffset != -1) dumpInt(pParse, level, "iOffset", p->iOffset);
+  level--;
+  printf("%s}\n", indent(level));
+}
+
+int sqlite3SelectDump(Parse *pParse, Select *p) {
+  char buf[256];
+  printf("sqlite3SelectDump Parse=%p, Select=%p\n", pParse, p);
+  sprintf(buf, "Select %p", p);
+  dumpSelect(pParse, 0, buf, p);
+  return 0;
+}
+
+
 /*
 ** Delete all the content of a Select structure but do not deallocate
 ** the select structure itself.
@@ -2304,6 +2843,10 @@ static int flattenSubquery(
   ** success.
   */
   sqlite3SelectDelete(pSub);
+
+  printf("\nSelect tree after successful flattenSubquery():\n");
+  sqlite3SelectDump(NULL, p);
+
   return 1;
 }
 #endif /* SQLITE_OMIT_VIEW */
Index: src/sqliteInt.h
===================================================================
RCS file: /sqlite/sqlite/src/sqliteInt.h,v
retrieving revision 1.521
diff -u -3 -p -r1.521 sqliteInt.h
--- src/sqliteInt.h     11 Jul 2006 14:17:52 -0000      1.521
+++ src/sqliteInt.h     24 Jul 2006 03:15:54 -0000
@@ -1621,6 +1621,7 @@ void sqlite3DropIndex(Parse*, SrcList*, 
 void sqlite3AddKeyType(Vdbe*, ExprList*);
 void sqlite3AddIdxKeyType(Vdbe*, Index*);
 int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
+int sqlite3SelectDump(Parse*, Select*);
 Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
                         int,Expr*,Expr*);
 void sqlite3SelectDelete(Select*);

Reply via email to