From: drh Date: Tue, 1 May 2018 01:18:21 +0000 (+0000) Subject: The ".selecttrace 0x4000" command causes the AST to be output to stdout as X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fast-trace-demo;p=thirdparty%2Fsqlite.git The ".selecttrace 0x4000" command causes the AST to be output to stdout as a table with four columns. FossilOrigin-Name: 2a75e631eed603e8e21a5bb77f2a56ac9d9d5a1fd33cb24461b24c3bb9778703 --- diff --git a/manifest b/manifest index 64af0212bc..4cb3d90dba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\scases\sadded\sfor\sSQLITE_DBCONFIG_RESET_DATABASE. -D 2018-04-28T19:08:02.897 +C The\s".selecttrace\s0x4000"\scommand\scauses\sthe\sAST\sto\sbe\soutput\sto\sstdout\sas\na\stable\swith\sfour\scolumns. +D 2018-05-01T01:18:21.511 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 5ce9343cba9c189046f1afe6d2bcc1f68079439febc05267b98aec6ecc752439 @@ -493,12 +493,12 @@ F src/printf.c d3b7844ddeb11fbbdd38dd84d09c9c1ac171d21fb038473c3aa97981201cc660 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 6415381a0e9d22c0e7cba33ca4a53f81474190862f5d4838190f5eb5b0b47bc9 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c daf07d8defce3311f9e69f1280a874d78bc1d16c305f6aa689640f7afa02842f +F src/select.c f84fef1a0d69eff9ebf35b29d5261822869a20ba333db9d4da30c46d7a2a2493 F src/shell.c.in 54b902ab7d840f60ddfabc13124c85d4980342c88aff7679f2cc25f67c21ade7 F src/sqlite.h.in d669de545f18f2f01362de02e309cd7f15185958c71bac8f53cd5438b46d2bea F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 83a3c4ce93d650bedfd1aa558cb85a516bd6d094445ee989740827d0d944368d -F src/sqliteInt.h 8ac0138eae10337b745b03dad0124fd63ae911c0503e795729503e7fc6234d57 +F src/sqliteInt.h 9aef9530fc7f971d88770eef29dcf5b632ceedc67cf91649d8229e8cbc25df5c F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -556,7 +556,7 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c bbde32eac9eb1280f5292bcdfef66f5a57e43176cbf9347e0efab9f75e133f97 -F src/treeview.c 6cea286ca9af8b126dae9714799265353387244eba0d451c3cc2cd60946cc4c7 +F src/treeview.c c66a74b9cda27393607a58a4ba4d44875a862c0e0428827ce5840dd7a663834d F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995 F src/update.c 5be2f501ddc704fc04183bdb28b25eab930bb8553d973429a089ec94fa85cf2b F src/upsert.c ae4a4823b45c4daf87e8aea8c0f582a8844763271f5ed54ee5956c4c612734f4 @@ -1727,7 +1727,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 564ae8297d417ba4b7978e430d41f125007177673163f6ed9adc3a3974f73d24 -R f62951ddf79b7c70897c7cedc3fc5902 +P 08665a9e2e50a0a1e62529884cf65f8090debe89a306a3904b53268729ab5ad5 +R 43ceb6108f34ca0a76ce471754b59fcb +T *branch * ast-trace-demo +T *sym-ast-trace-demo * +T -sym-trunk * U drh -Z d48406f4893f856e5db8717a8971e33f +Z 05d2e828fe1abfa136e23bf30c643644 diff --git a/manifest.uuid b/manifest.uuid index c789d5b903..6bee54be0c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -08665a9e2e50a0a1e62529884cf65f8090debe89a306a3904b53268729ab5ad5 \ No newline at end of file +2a75e631eed603e8e21a5bb77f2a56ac9d9d5a1fd33cb24461b24c3bb9778703 \ No newline at end of file diff --git a/src/select.c b/src/select.c index ac313d0288..de634d9572 100644 --- a/src/select.c +++ b/src/select.c @@ -5494,6 +5494,10 @@ int sqlite3Select( if( pParse->iSelectId==0 && (sqlite3SelectTrace & 0x2000)!=0 ){ sqlite3TreeViewSelect(0, p, 0); } + if( pParse->iSelectId==0 && (sqlite3SelectTrace & 0x4000)!=0 ){ + int iNodeId = 0; + sqlite3AstSelect(p, &iNodeId, 0); + } #endif explainSetInteger(pParse->iSelectId, iRestoreSelectId); return rc; @@ -6288,6 +6292,10 @@ select_end: if( pParse->iSelectId==0 && (sqlite3SelectTrace & 0x2000)!=0 ){ sqlite3TreeViewSelect(0, p, 0); } + if( pParse->iSelectId==0 && (sqlite3SelectTrace & 0x4000)!=0 ){ + int iNodeId = 0; + sqlite3AstSelect(p, &iNodeId, 0); + } #endif explainSetInteger(pParse->iSelectId, iRestoreSelectId); return rc; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c700c261b8..b67330f6d4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3678,6 +3678,11 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list); void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); void sqlite3TreeViewSelect(TreeView*, const Select*, u8); void sqlite3TreeViewWith(TreeView*, const With*, u8); + + void sqlite3AstExpr(const Expr*,int*,int); + void sqlite3AstExprList(const ExprList*,int*,int,int); + void sqlite3AstSelect(const Select*,int*,int); + void sqlite3AstWith(const With*,int*,int); #endif diff --git a/src/treeview.c b/src/treeview.c index 51fa7f06ca..4b1d1781d6 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -570,4 +570,488 @@ void sqlite3TreeViewExprList( sqlite3TreeViewPop(pView); } +/**************************************************************************** +** Experimental (demonstration-only) routines for printing a AST as a +** relation: +** +** CREATE TABLE AstNode( +** nodeId INTEGER PRIMARY KEY, +** parentId INTEGER REFERENCES AstNode, +** name TEXT, +** value ANY +** ); +*/ + +#define ASTVT_NULL 0 +#define ASTVT_TEXT 1 +#define ASTVT_INT 2 + +/* +** Output a single row of the AstNode relation +*/ +static int sqlite3AstOneRow( + int *pNodeCnt, + int parentId, + const char *zName, + int eValtype, + int iValue, + const char *zValue +){ + int nodeId = ++(*pNodeCnt); + printf("%d,", nodeId); + if( parentId ){ + printf("%d,", parentId); + }else{ + printf("NULL,"); + } + printf("'%s',", zName); + switch( eValtype ){ + case ASTVT_INT: printf("%d\n", iValue); break; + case ASTVT_TEXT: printf("'%s'\n", zValue); break; + default: printf("NULL\n"); break; + } + return nodeId; +} +static int sqlite3AstOneRowInt( + int *pNodeCnt, + int parentId, + const char *zName, + int iValue +){ + return sqlite3AstOneRow(pNodeCnt,parentId,zName,ASTVT_INT,iValue,0); +} +static int sqlite3AstOneRowText( + int *pNodeCnt, + int parentId, + const char *zName, + const char *zValue +){ + return sqlite3AstOneRow(pNodeCnt,parentId,zName,ASTVT_TEXT,0,zValue); +} +static int sqlite3AstOneRowNull( + int *pNodeCnt, + int parentId, + const char *zName +){ + return sqlite3AstOneRow(pNodeCnt,parentId,zName,ASTVT_NULL,0,0); +} +static int sqlite3AstOneRowOp( + int *pNodeCnt, + int parentId, + const char *zName, + const Expr *pExpr +){ + char zFlg[30]; + sqlite3_snprintf(sizeof(zFlg),zFlg,"0x%6x",pExpr->flags); + return sqlite3AstOneRow(pNodeCnt,parentId,zName,ASTVT_TEXT,0,zFlg); +} + + +void sqlite3AstExpr(const Expr *pExpr, int *pNodeCnt, int iParentId){ + int iNodeId; + const char *zBinOp = 0; + const char *zUniOp = 0; + + if( pExpr==0 ) return; + switch( pExpr->op ){ + case TK_AGG_COLUMN: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "agg_column", pExpr); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "table", pExpr->iTable); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "column", pExpr->iColumn); + break; + } + case TK_COLUMN: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "column", pExpr); + if( pExpr->iTable>=0 ){ + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "table", pExpr->iTable); + } + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "column", pExpr->iColumn); + break; + } + case TK_INTEGER: { + if( pExpr->flags & EP_IntValue ){ + iNodeId = sqlite3AstOneRowInt(pNodeCnt, iParentId, + "integer", pExpr->u.iValue); + }else{ + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, + "integer", pExpr->u.zToken); + } + break; + } +#ifndef SQLITE_OMIT_FLOATING_POINT + case TK_FLOAT: { + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, + "float", pExpr->u.zToken); + break; + } +#endif + case TK_STRING: { + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, + "string", pExpr->u.zToken); + break; + } + case TK_NULL: { + iNodeId = sqlite3AstOneRowNull(pNodeCnt, iParentId, "null"); + break; + } + case TK_TRUEFALSE: { + iNodeId = sqlite3AstOneRowNull(pNodeCnt, iParentId, + sqlite3ExprTruthValue(pExpr) ? "true" : "false"); + break; + } +#ifndef SQLITE_OMIT_BLOB_LITERAL + case TK_BLOB: { + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, "blob", + pExpr->u.zToken); + break; + } +#endif + case TK_VARIABLE: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "variable", pExpr); + sqlite3AstOneRowText(pNodeCnt, iNodeId, "name", pExpr->u.zToken); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "column", pExpr->iColumn); + break; + } + case TK_REGISTER: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "register", pExpr); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "registerNumber", + pExpr->iTable); + break; + } + case TK_ID: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "id", pExpr); + sqlite3AstOneRowText(pNodeCnt, iNodeId, "Name", pExpr->u.zToken); + break; + } + 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_DOT: zBinOp = "DOT"; break; + + case TK_CAST: zUniOp = "CAST"; 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_IF_NULL_ROW: zUniOp = "IFNULLROW"; break; + + case TK_TRUTH: { + int x; + const char *azOp[] = { + "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" + }; + assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); + assert( pExpr->pRight ); + assert( pExpr->pRight->op==TK_TRUEFALSE ); + x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); + zUniOp = azOp[x]; + break; + } + + case TK_SPAN: { + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, "span", + pExpr->u.zToken); + sqlite3AstExpr(pExpr->pLeft, pNodeCnt, iNodeId); + break; + } + + case TK_COLLATE: { + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, "collate", + pExpr->u.zToken); + sqlite3AstExpr(pExpr->pLeft, pNodeCnt, iNodeId); + break; + } + + case TK_AGG_FUNCTION: + case TK_FUNCTION: { + ExprList *pFarg; /* List of function arguments */ + if( ExprHasProperty(pExpr, EP_TokenOnly) ){ + pFarg = 0; + }else{ + pFarg = pExpr->x.pList; + } + if( pExpr->op==TK_AGG_FUNCTION ){ + char zId[20]; + sqlite3_snprintf(sizeof(zId),zId,"agg_function%d", pExpr->op2); + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, zId, + pExpr->u.zToken); + }else{ + iNodeId = sqlite3AstOneRowText(pNodeCnt, iParentId, "function", + pExpr->u.zToken); + } + if( pFarg ){ + sqlite3AstExprList(pFarg, pNodeCnt, iNodeId, 0); + } + break; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_EXISTS: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "exists-expr", pExpr); + sqlite3AstSelect(pExpr->x.pSelect, pNodeCnt, iNodeId); + break; + } + case TK_SELECT: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "select-expr", pExpr); + sqlite3AstSelect(pExpr->x.pSelect, pNodeCnt, iNodeId); + break; + } + case TK_IN: { + int id; + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "in", pExpr); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "left"); + sqlite3AstExpr(pExpr->pLeft, pNodeCnt, id); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "right"); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + sqlite3AstSelect(pExpr->x.pSelect, pNodeCnt, id); + }else{ + sqlite3AstExprList(pExpr->x.pList, pNodeCnt, id, 0); + } + 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: { + int id; + Expr *pX = pExpr->pLeft; + Expr *pY = pExpr->x.pList->a[0].pExpr; + Expr *pZ = pExpr->x.pList->a[1].pExpr; + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "between", pExpr); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "left"); + sqlite3AstExpr(pX, pNodeCnt, id); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "lower"); + sqlite3AstExpr(pY, pNodeCnt, id); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "upper"); + sqlite3AstExpr(pZ, pNodeCnt, id); + 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. + */ + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, + pExpr->iTable ? "new-column" : "old-column", pExpr); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "column", pExpr->iColumn); + break; + } + case TK_CASE: { + int id; + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "case", pExpr); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "left"); + sqlite3AstExpr(pExpr->pLeft, pNodeCnt, id); + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "list"); + sqlite3AstExprList(pExpr->x.pList, pNodeCnt, id, 0); + break; + } + 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; + } + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "raise", pExpr); + sqlite3AstOneRowText(pNodeCnt, iNodeId, "type", zType); + sqlite3AstOneRowText(pNodeCnt, iNodeId, "arg", pExpr->u.zToken); + break; + } + case TK_MATCH: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "match", pExpr); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "table", pExpr->iTable); + sqlite3AstOneRowInt(pNodeCnt, iNodeId, "column", pExpr->iColumn); + break; + } + case TK_VECTOR: { + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, "vector", pExpr); + sqlite3AstExprList(pExpr->x.pList, pNodeCnt, iNodeId, 0); + break; + } + case TK_SELECT_COLUMN: { + iNodeId = sqlite3AstOneRowInt(pNodeCnt, iParentId, "select-column", + pExpr->iColumn); + sqlite3AstSelect(pExpr->pLeft->x.pSelect, pNodeCnt, iNodeId); + break; + } + default: { + sqlite3AstOneRowInt(pNodeCnt, iParentId, "unknown", pExpr->op); + break; + } + } + if( zBinOp ){ + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, zBinOp, pExpr); + if( pExpr->pLeft ){ + int id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "left"); + sqlite3AstExpr(pExpr->pLeft, pNodeCnt, id); + } + if( pExpr->pRight ){ + int id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "right"); + sqlite3AstExpr(pExpr->pRight, pNodeCnt, id); + } + } + if( zUniOp ){ + iNodeId = sqlite3AstOneRowOp(pNodeCnt, iParentId, zUniOp, pExpr); + if( pExpr->pLeft ){ + sqlite3AstExpr(pExpr->pLeft, pNodeCnt, iNodeId); + } + } +} + +void sqlite3AstExprList( + const ExprList *pList, + int *pNodeCnt, + int iParentId, + int showSortOrder +){ + int i; + if( pList==0 ) return; + for(i=0; inExpr; i++){ + const struct ExprList_item *pItem = pList->a + i; + int id = sqlite3AstOneRowNull(pNodeCnt, iParentId, "listitem"); + if( pItem->zName && pItem->zName[0] ){ + sqlite3AstOneRowText(pNodeCnt, id, "name", pItem->zName); + } + if( showSortOrder && pItem->sortOrder ){ + sqlite3AstOneRowInt(pNodeCnt, id, "desc", 1); + } + sqlite3AstExpr(pList->a[i].pExpr, pNodeCnt, id); + } +} + + +/* +** Generate a human-readable description of a WITH clause. +*/ +void sqlite3AstWith(const With *pWith, int *pNodeCnt, int iParentId){ + int i; + if( pWith==0 ) return; + if( pWith->nCte==0 ) return; + if( pWith && pWith->nCte>0 ){ + int iNodeId = sqlite3AstOneRowNull(pNodeCnt, iParentId, "WITH"); + for(i=0; inCte; i++){ + const struct Cte *pCte = &pWith->a[i]; + int id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "with-cte"); + sqlite3AstOneRowText(pNodeCnt, id, "name", pCte->zName); + if( pCte->pCols && pCte->pCols->nExpr>0 ){ + int x = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "column-list"); + sqlite3AstExprList(pCte->pCols, pNodeCnt, x, 0); + } + sqlite3AstSelect(pCte->pSelect, pNodeCnt, iNodeId); + } + } +} + + +/* +** Generate a human-readable description of a Select object. +*/ +void sqlite3AstSelect(const Select *p, int *pNodeCnt, int iParentId){ + if( p==0 ) return; + if( p->pWith ){ + sqlite3AstWith(p->pWith, pNodeCnt, iParentId); + } + do{ + int iNodeId = sqlite3AstOneRowNull(pNodeCnt, iParentId, "SELECT"); + int id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "result-set"); + sqlite3AstExprList(p->pEList, pNodeCnt, id, 0); + if( p->pSrc && p->pSrc->nSrc ){ + int i; + for(i=0; ipSrc->nSrc; i++){ + struct SrcList_item *pItem = &p->pSrc->a[i]; + int iFrom = sqlite3AstOneRowInt(pNodeCnt, iNodeId, + "from-item", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3AstOneRowText(pNodeCnt, iFrom, "database", pItem->zDatabase); + } + if( pItem->zName ){ + sqlite3AstOneRowText(pNodeCnt, iFrom, "name", pItem->zName); + } + if( pItem->pTab ){ + sqlite3AstOneRowText(pNodeCnt, iFrom, "tabname", pItem->pTab->zName); + } + if( pItem->zAlias ){ + sqlite3AstOneRowText(pNodeCnt, iFrom, "as", pItem->zAlias); + } + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3AstOneRowInt(pNodeCnt, iFrom, "left-join", 1); + } + if( pItem->pSelect ){ + sqlite3AstSelect(pItem->pSelect, pNodeCnt, iFrom); + } + if( pItem->fg.isTabFunc ){ + int x = sqlite3AstOneRowNull(pNodeCnt, iFrom, "func-args"); + sqlite3AstExprList(pItem->u1.pFuncArg, pNodeCnt, x, 0); + } + } + } + if( p->pWhere ){ + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "where"); + sqlite3AstExpr(p->pWhere, pNodeCnt, id); + } + if( p->pGroupBy ){ + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "groupby"); + sqlite3AstExprList(p->pGroupBy, pNodeCnt, id, 0); + } + if( p->pHaving ){ + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "having"); + sqlite3AstExpr(p->pHaving, pNodeCnt, id); + } + if( p->pOrderBy ){ + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "orderby"); + sqlite3AstExprList(p->pOrderBy, pNodeCnt, id, 1); + } + if( p->pLimit ){ + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "limit"); + sqlite3AstExpr(p->pLimit->pLeft, pNodeCnt, id); + if( p->pLimit->pRight ){ + id = sqlite3AstOneRowNull(pNodeCnt, iNodeId, "offset"); + sqlite3AstExpr(p->pLimit->pRight, pNodeCnt, id); + } + } + if( p->pPrior ){ + const char *zOp = "UNION"; + switch( p->op ){ + case TK_ALL: zOp = "UNION ALL"; break; + case TK_INTERSECT: zOp = "INTERSECT"; break; + case TK_EXCEPT: zOp = "EXCEPT"; break; + } + iParentId = sqlite3AstOneRowNull(pNodeCnt, iNodeId, zOp); + } + p = p->pPrior; + }while( p!=0 ); +} + #endif /* SQLITE_DEBUG */