138b4149cSdrh /* 238b4149cSdrh ** 2015-06-08 338b4149cSdrh ** 438b4149cSdrh ** The author disclaims copyright to this source code. In place of 538b4149cSdrh ** a legal notice, here is a blessing: 638b4149cSdrh ** 738b4149cSdrh ** May you do good and not evil. 838b4149cSdrh ** May you find forgiveness for yourself and forgive others. 938b4149cSdrh ** May you share freely, never taking more than you give. 1038b4149cSdrh ** 1138b4149cSdrh ************************************************************************* 1238b4149cSdrh ** 1338b4149cSdrh ** This file contains C code to implement the TreeView debugging routines. 1438b4149cSdrh ** These routines print a parse tree to standard output for debugging and 1538b4149cSdrh ** analysis. 1638b4149cSdrh ** 1738b4149cSdrh ** The interfaces in this file is only available when compiling 1838b4149cSdrh ** with SQLITE_DEBUG. 1938b4149cSdrh */ 2038b4149cSdrh #include "sqliteInt.h" 2138b4149cSdrh #ifdef SQLITE_DEBUG 2238b4149cSdrh 2338b4149cSdrh /* 2438b4149cSdrh ** Add a new subitem to the tree. The moreToFollow flag indicates that this 2538b4149cSdrh ** is not the last item in the tree. 2638b4149cSdrh */ 2738b4149cSdrh static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ 2838b4149cSdrh if( p==0 ){ 2938b4149cSdrh p = sqlite3_malloc64( sizeof(*p) ); 3038b4149cSdrh if( p==0 ) return 0; 3138b4149cSdrh memset(p, 0, sizeof(*p)); 3238b4149cSdrh }else{ 3338b4149cSdrh p->iLevel++; 3438b4149cSdrh } 3538b4149cSdrh assert( moreToFollow==0 || moreToFollow==1 ); 3638b4149cSdrh if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; 3738b4149cSdrh return p; 3838b4149cSdrh } 3938b4149cSdrh 4038b4149cSdrh /* 4138b4149cSdrh ** Finished with one layer of the tree 4238b4149cSdrh */ 4338b4149cSdrh static void sqlite3TreeViewPop(TreeView *p){ 4438b4149cSdrh if( p==0 ) return; 4538b4149cSdrh p->iLevel--; 4638b4149cSdrh if( p->iLevel<0 ) sqlite3_free(p); 4738b4149cSdrh } 4838b4149cSdrh 4938b4149cSdrh /* 5038b4149cSdrh ** Generate a single line of output for the tree, with a prefix that contains 5138b4149cSdrh ** all the appropriate tree lines 5238b4149cSdrh */ 5338b4149cSdrh static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ 5438b4149cSdrh va_list ap; 5538b4149cSdrh int i; 5638b4149cSdrh StrAccum acc; 5738b4149cSdrh char zBuf[500]; 5838b4149cSdrh sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); 5938b4149cSdrh if( p ){ 6038b4149cSdrh for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){ 610cdbe1aeSdrh sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4); 6238b4149cSdrh } 630cdbe1aeSdrh sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); 6438b4149cSdrh } 65fbe07539Sdrh if( zFormat!=0 ){ 6638b4149cSdrh va_start(ap, zFormat); 670cdbe1aeSdrh sqlite3_str_vappendf(&acc, zFormat, ap); 6838b4149cSdrh va_end(ap); 6910c0e711Sdrh assert( acc.nChar>0 || acc.accError ); 700cdbe1aeSdrh sqlite3_str_append(&acc, "\n", 1); 71fbe07539Sdrh } 7238b4149cSdrh sqlite3StrAccumFinish(&acc); 7338b4149cSdrh fprintf(stdout,"%s", zBuf); 7438b4149cSdrh fflush(stdout); 7538b4149cSdrh } 7638b4149cSdrh 7738b4149cSdrh /* 7838b4149cSdrh ** Shorthand for starting a new tree item that consists of a single label 7938b4149cSdrh */ 8038b4149cSdrh static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ 8138b4149cSdrh p = sqlite3TreeViewPush(p, moreFollows); 8238b4149cSdrh sqlite3TreeViewLine(p, "%s", zLabel); 8338b4149cSdrh } 8438b4149cSdrh 852476a6f2Sdrh /* 862476a6f2Sdrh ** Generate a human-readable description of a WITH clause. 872476a6f2Sdrh */ 882476a6f2Sdrh void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){ 892476a6f2Sdrh int i; 902476a6f2Sdrh if( pWith==0 ) return; 912476a6f2Sdrh if( pWith->nCte==0 ) return; 922476a6f2Sdrh if( pWith->pOuter ){ 932476a6f2Sdrh sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter); 942476a6f2Sdrh }else{ 952476a6f2Sdrh sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); 962476a6f2Sdrh } 972476a6f2Sdrh if( pWith->nCte>0 ){ 982476a6f2Sdrh pView = sqlite3TreeViewPush(pView, 1); 992476a6f2Sdrh for(i=0; i<pWith->nCte; i++){ 1002476a6f2Sdrh StrAccum x; 1012476a6f2Sdrh char zLine[1000]; 1022476a6f2Sdrh const struct Cte *pCte = &pWith->a[i]; 1032476a6f2Sdrh sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); 1040cdbe1aeSdrh sqlite3_str_appendf(&x, "%s", pCte->zName); 1052476a6f2Sdrh if( pCte->pCols && pCte->pCols->nExpr>0 ){ 1062476a6f2Sdrh char cSep = '('; 1072476a6f2Sdrh int j; 1082476a6f2Sdrh for(j=0; j<pCte->pCols->nExpr; j++){ 10941cee668Sdrh sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName); 1102476a6f2Sdrh cSep = ','; 1112476a6f2Sdrh } 1120cdbe1aeSdrh sqlite3_str_appendf(&x, ")"); 1132476a6f2Sdrh } 114a79e2a2dSdrh if( pCte->pUse ){ 115a79e2a2dSdrh sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, 116a79e2a2dSdrh pCte->pUse->nUse); 117a79e2a2dSdrh } 1182476a6f2Sdrh sqlite3StrAccumFinish(&x); 1192476a6f2Sdrh sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); 1202476a6f2Sdrh sqlite3TreeViewSelect(pView, pCte->pSelect, 0); 1212476a6f2Sdrh sqlite3TreeViewPop(pView); 1222476a6f2Sdrh } 1232476a6f2Sdrh sqlite3TreeViewPop(pView); 1242476a6f2Sdrh } 1252476a6f2Sdrh } 1262476a6f2Sdrh 127145d0a35Sdrh /* 128145d0a35Sdrh ** Generate a human-readable description of a SrcList object. 129145d0a35Sdrh */ 130145d0a35Sdrh void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ 131145d0a35Sdrh int i; 132145d0a35Sdrh for(i=0; i<pSrc->nSrc; i++){ 1337601294aSdrh const SrcItem *pItem = &pSrc->a[i]; 134145d0a35Sdrh StrAccum x; 135145d0a35Sdrh char zLine[100]; 136145d0a35Sdrh sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); 137ff374918Sdrh x.printfFlags |= SQLITE_PRINTF_INTERNAL; 1386610e6a5Sdrh sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); 139145d0a35Sdrh if( pItem->pTab ){ 140f7f6dbf5Sdrh sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", 141f7f6dbf5Sdrh pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); 142145d0a35Sdrh } 143145d0a35Sdrh if( pItem->fg.jointype & JT_LEFT ){ 144145d0a35Sdrh sqlite3_str_appendf(&x, " LEFT-JOIN"); 1459b9f2351Sdrh }else if( pItem->fg.jointype & JT_CROSS ){ 1469b9f2351Sdrh sqlite3_str_appendf(&x, " CROSS-JOIN"); 147145d0a35Sdrh } 148b7e51995Sdrh if( pItem->fg.fromDDL ){ 149b7e51995Sdrh sqlite3_str_appendf(&x, " DDL"); 150b7e51995Sdrh } 151a79e2a2dSdrh if( pItem->fg.isCte ){ 152a79e2a2dSdrh sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse); 153a79e2a2dSdrh } 154145d0a35Sdrh sqlite3StrAccumFinish(&x); 155145d0a35Sdrh sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); 156145d0a35Sdrh if( pItem->pSelect ){ 157145d0a35Sdrh sqlite3TreeViewSelect(pView, pItem->pSelect, 0); 158145d0a35Sdrh } 159145d0a35Sdrh if( pItem->fg.isTabFunc ){ 160145d0a35Sdrh sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); 161145d0a35Sdrh } 162145d0a35Sdrh sqlite3TreeViewPop(pView); 163145d0a35Sdrh } 164145d0a35Sdrh } 16538b4149cSdrh 16638b4149cSdrh /* 1672e5c5052Sdrh ** Generate a human-readable description of a Select object. 16838b4149cSdrh */ 16938b4149cSdrh void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ 17038b4149cSdrh int n = 0; 1711c4505deSdrh int cnt = 0; 172510b7ff5Sdrh if( p==0 ){ 173510b7ff5Sdrh sqlite3TreeViewLine(pView, "nil-SELECT"); 174510b7ff5Sdrh return; 175510b7ff5Sdrh } 17638b4149cSdrh pView = sqlite3TreeViewPush(pView, moreToFollow); 1772476a6f2Sdrh if( p->pWith ){ 1782476a6f2Sdrh sqlite3TreeViewWith(pView, p->pWith, 1); 1792476a6f2Sdrh cnt = 1; 1802476a6f2Sdrh sqlite3TreeViewPush(pView, 1); 1812476a6f2Sdrh } 1821c4505deSdrh do{ 18355b4c827Sdrh if( p->selFlags & SF_WhereBegin ){ 18455b4c827Sdrh sqlite3TreeViewLine(pView, "sqlite3WhereBegin()"); 18555b4c827Sdrh }else{ 186926961dcSdrh sqlite3TreeViewLine(pView, 187fef37760Sdrh "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d", 188926961dcSdrh ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), 189926961dcSdrh ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), 190fef37760Sdrh p->selId, p, p->selFlags, 191926961dcSdrh (int)p->nSelectRow 192926961dcSdrh ); 19355b4c827Sdrh } 1941c4505deSdrh if( cnt++ ) sqlite3TreeViewPop(pView); 1951c4505deSdrh if( p->pPrior ){ 1961c4505deSdrh n = 1000; 1971c4505deSdrh }else{ 1981c4505deSdrh n = 0; 19938b4149cSdrh if( p->pSrc && p->pSrc->nSrc ) n++; 20038b4149cSdrh if( p->pWhere ) n++; 20138b4149cSdrh if( p->pGroupBy ) n++; 20238b4149cSdrh if( p->pHaving ) n++; 20338b4149cSdrh if( p->pOrderBy ) n++; 20438b4149cSdrh if( p->pLimit ) n++; 205a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 206a1fd4b52Sdrh if( p->pWin ) n++; 207a1fd4b52Sdrh if( p->pWinDefn ) n++; 208a1fd4b52Sdrh #endif 2091c4505deSdrh } 21055b4c827Sdrh if( p->pEList ){ 21155b4c827Sdrh sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set"); 21255b4c827Sdrh } 21355b4c827Sdrh n--; 214a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 215a1fd4b52Sdrh if( p->pWin ){ 216a1fd4b52Sdrh Window *pX; 217a1fd4b52Sdrh pView = sqlite3TreeViewPush(pView, (n--)>0); 218a1fd4b52Sdrh sqlite3TreeViewLine(pView, "window-functions"); 219a1fd4b52Sdrh for(pX=p->pWin; pX; pX=pX->pNextWin){ 220a1fd4b52Sdrh sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); 221a1fd4b52Sdrh } 222a1fd4b52Sdrh sqlite3TreeViewPop(pView); 223a1fd4b52Sdrh } 224a1fd4b52Sdrh #endif 22538b4149cSdrh if( p->pSrc && p->pSrc->nSrc ){ 22638b4149cSdrh pView = sqlite3TreeViewPush(pView, (n--)>0); 22738b4149cSdrh sqlite3TreeViewLine(pView, "FROM"); 228145d0a35Sdrh sqlite3TreeViewSrcList(pView, p->pSrc); 22938b4149cSdrh sqlite3TreeViewPop(pView); 23038b4149cSdrh } 23138b4149cSdrh if( p->pWhere ){ 23238b4149cSdrh sqlite3TreeViewItem(pView, "WHERE", (n--)>0); 23338b4149cSdrh sqlite3TreeViewExpr(pView, p->pWhere, 0); 23438b4149cSdrh sqlite3TreeViewPop(pView); 23538b4149cSdrh } 23638b4149cSdrh if( p->pGroupBy ){ 23738b4149cSdrh sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); 23838b4149cSdrh } 23938b4149cSdrh if( p->pHaving ){ 24038b4149cSdrh sqlite3TreeViewItem(pView, "HAVING", (n--)>0); 24138b4149cSdrh sqlite3TreeViewExpr(pView, p->pHaving, 0); 24238b4149cSdrh sqlite3TreeViewPop(pView); 24338b4149cSdrh } 244a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 245a1fd4b52Sdrh if( p->pWinDefn ){ 246a1fd4b52Sdrh Window *pX; 247a1fd4b52Sdrh sqlite3TreeViewItem(pView, "WINDOW", (n--)>0); 248a1fd4b52Sdrh for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ 249a1fd4b52Sdrh sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); 250a1fd4b52Sdrh } 251a1fd4b52Sdrh sqlite3TreeViewPop(pView); 252a1fd4b52Sdrh } 253a1fd4b52Sdrh #endif 25438b4149cSdrh if( p->pOrderBy ){ 25538b4149cSdrh sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); 25638b4149cSdrh } 25738b4149cSdrh if( p->pLimit ){ 25838b4149cSdrh sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); 2598c0833fbSdrh sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0); 2608c0833fbSdrh if( p->pLimit->pRight ){ 2618c0833fbSdrh sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); 2628c0833fbSdrh sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); 26338b4149cSdrh sqlite3TreeViewPop(pView); 26438b4149cSdrh } 26538b4149cSdrh sqlite3TreeViewPop(pView); 26638b4149cSdrh } 26738b4149cSdrh if( p->pPrior ){ 26838b4149cSdrh const char *zOp = "UNION"; 26938b4149cSdrh switch( p->op ){ 27038b4149cSdrh case TK_ALL: zOp = "UNION ALL"; break; 27138b4149cSdrh case TK_INTERSECT: zOp = "INTERSECT"; break; 27238b4149cSdrh case TK_EXCEPT: zOp = "EXCEPT"; break; 27338b4149cSdrh } 2741c4505deSdrh sqlite3TreeViewItem(pView, zOp, 1); 27538b4149cSdrh } 2761c4505deSdrh p = p->pPrior; 2771c4505deSdrh }while( p!=0 ); 27838b4149cSdrh sqlite3TreeViewPop(pView); 27938b4149cSdrh } 28038b4149cSdrh 281a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 282a1fd4b52Sdrh /* 283a1fd4b52Sdrh ** Generate a description of starting or stopping bounds 284a1fd4b52Sdrh */ 285a1fd4b52Sdrh void sqlite3TreeViewBound( 286a1fd4b52Sdrh TreeView *pView, /* View context */ 287a1fd4b52Sdrh u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */ 288a1fd4b52Sdrh Expr *pExpr, /* Value for PRECEDING or FOLLOWING */ 289a1fd4b52Sdrh u8 moreToFollow /* True if more to follow */ 290a1fd4b52Sdrh ){ 291a1fd4b52Sdrh switch( eBound ){ 292a1fd4b52Sdrh case TK_UNBOUNDED: { 293a1fd4b52Sdrh sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow); 294a1fd4b52Sdrh sqlite3TreeViewPop(pView); 295a1fd4b52Sdrh break; 296a1fd4b52Sdrh } 297a1fd4b52Sdrh case TK_CURRENT: { 298a1fd4b52Sdrh sqlite3TreeViewItem(pView, "CURRENT", moreToFollow); 299a1fd4b52Sdrh sqlite3TreeViewPop(pView); 300a1fd4b52Sdrh break; 301a1fd4b52Sdrh } 302a1fd4b52Sdrh case TK_PRECEDING: { 303a1fd4b52Sdrh sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow); 304a1fd4b52Sdrh sqlite3TreeViewExpr(pView, pExpr, 0); 305a1fd4b52Sdrh sqlite3TreeViewPop(pView); 306a1fd4b52Sdrh break; 307a1fd4b52Sdrh } 308a1fd4b52Sdrh case TK_FOLLOWING: { 309a1fd4b52Sdrh sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow); 310a1fd4b52Sdrh sqlite3TreeViewExpr(pView, pExpr, 0); 311a1fd4b52Sdrh sqlite3TreeViewPop(pView); 312a1fd4b52Sdrh break; 313a1fd4b52Sdrh } 314a1fd4b52Sdrh } 315a1fd4b52Sdrh } 316a1fd4b52Sdrh #endif /* SQLITE_OMIT_WINDOWFUNC */ 317a1fd4b52Sdrh 318a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 319a1fd4b52Sdrh /* 320a1fd4b52Sdrh ** Generate a human-readable explanation for a Window object 321a1fd4b52Sdrh */ 322a1fd4b52Sdrh void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ 323fc15f4c5Sdrh int nElement = 0; 3240dc0e9c2Sdrh if( pWin->pFilter ){ 3250dc0e9c2Sdrh sqlite3TreeViewItem(pView, "FILTER", 1); 3260dc0e9c2Sdrh sqlite3TreeViewExpr(pView, pWin->pFilter, 0); 3270dc0e9c2Sdrh sqlite3TreeViewPop(pView); 3280dc0e9c2Sdrh } 329a1fd4b52Sdrh pView = sqlite3TreeViewPush(pView, more); 330a1fd4b52Sdrh if( pWin->zName ){ 3316f1644c0Sdrh sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); 332a1fd4b52Sdrh }else{ 3336f1644c0Sdrh sqlite3TreeViewLine(pView, "OVER (%p)", pWin); 334a1fd4b52Sdrh } 335fc15f4c5Sdrh if( pWin->zBase ) nElement++; 336fc15f4c5Sdrh if( pWin->pOrderBy ) nElement++; 337fc15f4c5Sdrh if( pWin->eFrmType ) nElement++; 338fc15f4c5Sdrh if( pWin->eExclude ) nElement++; 339fc15f4c5Sdrh if( pWin->zBase ){ 340fc15f4c5Sdrh sqlite3TreeViewPush(pView, (--nElement)>0); 341fc15f4c5Sdrh sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); 342fc15f4c5Sdrh sqlite3TreeViewPop(pView); 343fc15f4c5Sdrh } 344a1fd4b52Sdrh if( pWin->pPartition ){ 345fc15f4c5Sdrh sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY"); 346a1fd4b52Sdrh } 347a1fd4b52Sdrh if( pWin->pOrderBy ){ 348fc15f4c5Sdrh sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); 349a1fd4b52Sdrh } 350fc15f4c5Sdrh if( pWin->eFrmType ){ 3510dc0e9c2Sdrh char zBuf[30]; 352fc15f4c5Sdrh const char *zFrmType = "ROWS"; 353fc15f4c5Sdrh if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; 354fc15f4c5Sdrh if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS"; 3550dc0e9c2Sdrh sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType, 3560dc0e9c2Sdrh pWin->bImplicitFrame ? " (implied)" : ""); 3570dc0e9c2Sdrh sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); 358a1fd4b52Sdrh sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); 359a1fd4b52Sdrh sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); 360a1fd4b52Sdrh sqlite3TreeViewPop(pView); 361a1fd4b52Sdrh } 362fc15f4c5Sdrh if( pWin->eExclude ){ 363fc15f4c5Sdrh char zBuf[30]; 364fc15f4c5Sdrh const char *zExclude; 365fc15f4c5Sdrh switch( pWin->eExclude ){ 366fc15f4c5Sdrh case TK_NO: zExclude = "NO OTHERS"; break; 367fc15f4c5Sdrh case TK_CURRENT: zExclude = "CURRENT ROW"; break; 368fc15f4c5Sdrh case TK_GROUP: zExclude = "GROUP"; break; 369fc15f4c5Sdrh case TK_TIES: zExclude = "TIES"; break; 370fc15f4c5Sdrh default: 371fc15f4c5Sdrh sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude); 372fc15f4c5Sdrh zExclude = zBuf; 373fc15f4c5Sdrh break; 374fc15f4c5Sdrh } 375fc15f4c5Sdrh sqlite3TreeViewPush(pView, 0); 376fc15f4c5Sdrh sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); 377fc15f4c5Sdrh sqlite3TreeViewPop(pView); 378fc15f4c5Sdrh } 379a1fd4b52Sdrh sqlite3TreeViewPop(pView); 380a1fd4b52Sdrh } 381a1fd4b52Sdrh #endif /* SQLITE_OMIT_WINDOWFUNC */ 382a1fd4b52Sdrh 383a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 384a1fd4b52Sdrh /* 385a1fd4b52Sdrh ** Generate a human-readable explanation for a Window Function object 386a1fd4b52Sdrh */ 387a1fd4b52Sdrh void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ 388a1fd4b52Sdrh pView = sqlite3TreeViewPush(pView, more); 389a1fd4b52Sdrh sqlite3TreeViewLine(pView, "WINFUNC %s(%d)", 390a1fd4b52Sdrh pWin->pFunc->zName, pWin->pFunc->nArg); 391a1fd4b52Sdrh sqlite3TreeViewWindow(pView, pWin, 0); 392a1fd4b52Sdrh sqlite3TreeViewPop(pView); 393a1fd4b52Sdrh } 394a1fd4b52Sdrh #endif /* SQLITE_OMIT_WINDOWFUNC */ 395a1fd4b52Sdrh 39638b4149cSdrh /* 39738b4149cSdrh ** Generate a human-readable explanation of an expression tree. 39838b4149cSdrh */ 39938b4149cSdrh void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ 40038b4149cSdrh const char *zBinOp = 0; /* Binary operator */ 40138b4149cSdrh const char *zUniOp = 0; /* Unary operator */ 402e7375bfaSdrh char zFlgs[200]; 40338b4149cSdrh pView = sqlite3TreeViewPush(pView, moreToFollow); 40438b4149cSdrh if( pExpr==0 ){ 40538b4149cSdrh sqlite3TreeViewLine(pView, "nil"); 40638b4149cSdrh sqlite3TreeViewPop(pView); 40738b4149cSdrh return; 40838b4149cSdrh } 409e7375bfaSdrh if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){ 410b7e51995Sdrh StrAccum x; 411b7e51995Sdrh sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); 412b7e51995Sdrh sqlite3_str_appendf(&x, " fg.af=%x.%c", 4131194904bSdrh pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); 414b7e51995Sdrh if( ExprHasProperty(pExpr, EP_FromJoin) ){ 415b7e51995Sdrh sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable); 416d97cda43Sdrh } 417b7e51995Sdrh if( ExprHasProperty(pExpr, EP_FromDDL) ){ 418b7e51995Sdrh sqlite3_str_appendf(&x, " DDL"); 419b7e51995Sdrh } 420e7375bfaSdrh if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ 421e7375bfaSdrh sqlite3_str_appendf(&x, " IMMUTABLE"); 422e7375bfaSdrh } 423b7e51995Sdrh sqlite3StrAccumFinish(&x); 424b3d903ebSdrh }else{ 425b3d903ebSdrh zFlgs[0] = 0; 426b3d903ebSdrh } 42738b4149cSdrh switch( pExpr->op ){ 42838b4149cSdrh case TK_AGG_COLUMN: { 429b3d903ebSdrh sqlite3TreeViewLine(pView, "AGG{%d:%d}%s", 430b3d903ebSdrh pExpr->iTable, pExpr->iColumn, zFlgs); 43138b4149cSdrh break; 43238b4149cSdrh } 43338b4149cSdrh case TK_COLUMN: { 43438b4149cSdrh if( pExpr->iTable<0 ){ 43538b4149cSdrh /* This only happens when coding check constraints */ 436d493353eSdrh char zOp2[16]; 437d493353eSdrh if( pExpr->op2 ){ 438d493353eSdrh sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2); 439d493353eSdrh }else{ 440d493353eSdrh zOp2[0] = 0; 441d493353eSdrh } 442d493353eSdrh sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s", 443d493353eSdrh pExpr->iColumn, zFlgs, zOp2); 44438b4149cSdrh }else{ 445a513e591Sdrh sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s", 446a513e591Sdrh pExpr->iTable, pExpr->iColumn, 447a513e591Sdrh pExpr->y.pTab, zFlgs); 44838b4149cSdrh } 449efad2e23Sdrh if( ExprHasProperty(pExpr, EP_FixedCol) ){ 450efad2e23Sdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); 451efad2e23Sdrh } 45238b4149cSdrh break; 45338b4149cSdrh } 45438b4149cSdrh case TK_INTEGER: { 45538b4149cSdrh if( pExpr->flags & EP_IntValue ){ 45638b4149cSdrh sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); 45738b4149cSdrh }else{ 45838b4149cSdrh sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); 45938b4149cSdrh } 46038b4149cSdrh break; 46138b4149cSdrh } 46238b4149cSdrh #ifndef SQLITE_OMIT_FLOATING_POINT 46338b4149cSdrh case TK_FLOAT: { 46438b4149cSdrh sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); 46538b4149cSdrh break; 46638b4149cSdrh } 46738b4149cSdrh #endif 46838b4149cSdrh case TK_STRING: { 46938b4149cSdrh sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); 47038b4149cSdrh break; 47138b4149cSdrh } 47238b4149cSdrh case TK_NULL: { 47338b4149cSdrh sqlite3TreeViewLine(pView,"NULL"); 47438b4149cSdrh break; 47538b4149cSdrh } 47634328211Sdrh case TK_TRUEFALSE: { 47743c4ac8bSdrh sqlite3TreeViewLine(pView, 47896acafbeSdrh sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE"); 47934328211Sdrh break; 48034328211Sdrh } 48138b4149cSdrh #ifndef SQLITE_OMIT_BLOB_LITERAL 48238b4149cSdrh case TK_BLOB: { 48338b4149cSdrh sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); 48438b4149cSdrh break; 48538b4149cSdrh } 48638b4149cSdrh #endif 48738b4149cSdrh case TK_VARIABLE: { 48838b4149cSdrh sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", 48938b4149cSdrh pExpr->u.zToken, pExpr->iColumn); 49038b4149cSdrh break; 49138b4149cSdrh } 49238b4149cSdrh case TK_REGISTER: { 49338b4149cSdrh sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); 49438b4149cSdrh break; 49538b4149cSdrh } 49638b4149cSdrh case TK_ID: { 49738b4149cSdrh sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); 49838b4149cSdrh break; 49938b4149cSdrh } 50038b4149cSdrh #ifndef SQLITE_OMIT_CAST 50138b4149cSdrh case TK_CAST: { 50238b4149cSdrh /* Expressions of the form: CAST(pLeft AS token) */ 50338b4149cSdrh sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); 50438b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); 50538b4149cSdrh break; 50638b4149cSdrh } 50738b4149cSdrh #endif /* SQLITE_OMIT_CAST */ 50838b4149cSdrh case TK_LT: zBinOp = "LT"; break; 50938b4149cSdrh case TK_LE: zBinOp = "LE"; break; 51038b4149cSdrh case TK_GT: zBinOp = "GT"; break; 51138b4149cSdrh case TK_GE: zBinOp = "GE"; break; 51238b4149cSdrh case TK_NE: zBinOp = "NE"; break; 51338b4149cSdrh case TK_EQ: zBinOp = "EQ"; break; 51438b4149cSdrh case TK_IS: zBinOp = "IS"; break; 51538b4149cSdrh case TK_ISNOT: zBinOp = "ISNOT"; break; 51638b4149cSdrh case TK_AND: zBinOp = "AND"; break; 51738b4149cSdrh case TK_OR: zBinOp = "OR"; break; 51838b4149cSdrh case TK_PLUS: zBinOp = "ADD"; break; 51938b4149cSdrh case TK_STAR: zBinOp = "MUL"; break; 52038b4149cSdrh case TK_MINUS: zBinOp = "SUB"; break; 52138b4149cSdrh case TK_REM: zBinOp = "REM"; break; 52238b4149cSdrh case TK_BITAND: zBinOp = "BITAND"; break; 52338b4149cSdrh case TK_BITOR: zBinOp = "BITOR"; break; 52438b4149cSdrh case TK_SLASH: zBinOp = "DIV"; break; 52538b4149cSdrh case TK_LSHIFT: zBinOp = "LSHIFT"; break; 52638b4149cSdrh case TK_RSHIFT: zBinOp = "RSHIFT"; break; 52738b4149cSdrh case TK_CONCAT: zBinOp = "CONCAT"; break; 52838b4149cSdrh case TK_DOT: zBinOp = "DOT"; break; 529e7375bfaSdrh case TK_LIMIT: zBinOp = "LIMIT"; break; 53038b4149cSdrh 53138b4149cSdrh case TK_UMINUS: zUniOp = "UMINUS"; break; 53238b4149cSdrh case TK_UPLUS: zUniOp = "UPLUS"; break; 53338b4149cSdrh case TK_BITNOT: zUniOp = "BITNOT"; break; 53438b4149cSdrh case TK_NOT: zUniOp = "NOT"; break; 53538b4149cSdrh case TK_ISNULL: zUniOp = "ISNULL"; break; 53638b4149cSdrh case TK_NOTNULL: zUniOp = "NOTNULL"; break; 53738b4149cSdrh 53834328211Sdrh case TK_TRUTH: { 53943c4ac8bSdrh int x; 54043c4ac8bSdrh const char *azOp[] = { 54143c4ac8bSdrh "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" 54243c4ac8bSdrh }; 54334328211Sdrh assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); 54434328211Sdrh assert( pExpr->pRight ); 5456ece353fSdan assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); 54696acafbeSdrh x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); 54743c4ac8bSdrh zUniOp = azOp[x]; 54834328211Sdrh break; 54934328211Sdrh } 55034328211Sdrh 55194fa9c41Sdrh case TK_SPAN: { 55294fa9c41Sdrh sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); 55394fa9c41Sdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); 55494fa9c41Sdrh break; 55594fa9c41Sdrh } 55694fa9c41Sdrh 55738b4149cSdrh case TK_COLLATE: { 558c204d81aSdrh /* COLLATE operators without the EP_Collate flag are intended to 559018dbb17Sdrh ** emulate collation associated with a table column. These show 560018dbb17Sdrh ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE 561018dbb17Sdrh ** operators that appear in the original SQL always have the 562018dbb17Sdrh ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ 563c204d81aSdrh sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s", 564c204d81aSdrh !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "", 565c204d81aSdrh pExpr->u.zToken, zFlgs); 56638b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); 56738b4149cSdrh break; 56838b4149cSdrh } 56938b4149cSdrh 57038b4149cSdrh case TK_AGG_FUNCTION: 57138b4149cSdrh case TK_FUNCTION: { 57238b4149cSdrh ExprList *pFarg; /* List of function arguments */ 573a1fd4b52Sdrh Window *pWin; 57438b4149cSdrh if( ExprHasProperty(pExpr, EP_TokenOnly) ){ 57538b4149cSdrh pFarg = 0; 576a1fd4b52Sdrh pWin = 0; 57738b4149cSdrh }else{ 57838b4149cSdrh pFarg = pExpr->x.pList; 579a1fd4b52Sdrh #ifndef SQLITE_OMIT_WINDOWFUNC 580014fff20Sdrh pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; 581a1fd4b52Sdrh #else 582a1fd4b52Sdrh pWin = 0; 583a1fd4b52Sdrh #endif 58438b4149cSdrh } 58538b4149cSdrh if( pExpr->op==TK_AGG_FUNCTION ){ 586e26d428aSdrh sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p", 587ca74fbf6Sdrh pExpr->op2, pExpr->u.zToken, zFlgs, 588e26d428aSdrh pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0, 589ca74fbf6Sdrh pExpr->iAgg, pExpr->pAggInfo); 590d493353eSdrh }else if( pExpr->op2!=0 ){ 591d493353eSdrh const char *zOp2; 592d493353eSdrh char zBuf[8]; 593d493353eSdrh sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2); 594d493353eSdrh zOp2 = zBuf; 595d493353eSdrh if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck"; 596d493353eSdrh if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr"; 597d493353eSdrh if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx"; 598d493353eSdrh if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol"; 599d493353eSdrh sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s", 600d493353eSdrh pExpr->u.zToken, zFlgs, zOp2); 60138b4149cSdrh }else{ 60242d2fce7Sdrh sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs); 60338b4149cSdrh } 60438b4149cSdrh if( pFarg ){ 605a1fd4b52Sdrh sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); 60638b4149cSdrh } 6071489785bSmistachkin #ifndef SQLITE_OMIT_WINDOWFUNC 608a1fd4b52Sdrh if( pWin ){ 609a1fd4b52Sdrh sqlite3TreeViewWindow(pView, pWin, 0); 610a1fd4b52Sdrh } 611a1fd4b52Sdrh #endif 61238b4149cSdrh break; 61338b4149cSdrh } 61438b4149cSdrh #ifndef SQLITE_OMIT_SUBQUERY 61538b4149cSdrh case TK_EXISTS: { 6169f6e14c1Sdrh sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); 61738b4149cSdrh sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); 61838b4149cSdrh break; 61938b4149cSdrh } 62038b4149cSdrh case TK_SELECT: { 621a0365c48Sdrh sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags); 62238b4149cSdrh sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); 62338b4149cSdrh break; 62438b4149cSdrh } 62538b4149cSdrh case TK_IN: { 6269f6e14c1Sdrh sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); 62738b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); 62838b4149cSdrh if( ExprHasProperty(pExpr, EP_xIsSelect) ){ 62938b4149cSdrh sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); 63038b4149cSdrh }else{ 63138b4149cSdrh sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); 63238b4149cSdrh } 63338b4149cSdrh break; 63438b4149cSdrh } 63538b4149cSdrh #endif /* SQLITE_OMIT_SUBQUERY */ 63638b4149cSdrh 63738b4149cSdrh /* 63838b4149cSdrh ** x BETWEEN y AND z 63938b4149cSdrh ** 64038b4149cSdrh ** This is equivalent to 64138b4149cSdrh ** 64238b4149cSdrh ** x>=y AND x<=z 64338b4149cSdrh ** 64438b4149cSdrh ** X is stored in pExpr->pLeft. 64538b4149cSdrh ** Y is stored in pExpr->pList->a[0].pExpr. 64638b4149cSdrh ** Z is stored in pExpr->pList->a[1].pExpr. 64738b4149cSdrh */ 64838b4149cSdrh case TK_BETWEEN: { 64938b4149cSdrh Expr *pX = pExpr->pLeft; 65038b4149cSdrh Expr *pY = pExpr->x.pList->a[0].pExpr; 65138b4149cSdrh Expr *pZ = pExpr->x.pList->a[1].pExpr; 65238b4149cSdrh sqlite3TreeViewLine(pView, "BETWEEN"); 65338b4149cSdrh sqlite3TreeViewExpr(pView, pX, 1); 65438b4149cSdrh sqlite3TreeViewExpr(pView, pY, 1); 65538b4149cSdrh sqlite3TreeViewExpr(pView, pZ, 0); 65638b4149cSdrh break; 65738b4149cSdrh } 65838b4149cSdrh case TK_TRIGGER: { 65938b4149cSdrh /* If the opcode is TK_TRIGGER, then the expression is a reference 66038b4149cSdrh ** to a column in the new.* or old.* pseudo-tables available to 66138b4149cSdrh ** trigger programs. In this case Expr.iTable is set to 1 for the 66238b4149cSdrh ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn 66338b4149cSdrh ** is set to the column of the pseudo-table to read, or to -1 to 66438b4149cSdrh ** read the rowid field. 66538b4149cSdrh */ 66638b4149cSdrh sqlite3TreeViewLine(pView, "%s(%d)", 66738b4149cSdrh pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); 66838b4149cSdrh break; 66938b4149cSdrh } 67038b4149cSdrh case TK_CASE: { 67138b4149cSdrh sqlite3TreeViewLine(pView, "CASE"); 67238b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); 67338b4149cSdrh sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); 67438b4149cSdrh break; 67538b4149cSdrh } 67638b4149cSdrh #ifndef SQLITE_OMIT_TRIGGER 67738b4149cSdrh case TK_RAISE: { 67838b4149cSdrh const char *zType = "unk"; 6791194904bSdrh switch( pExpr->affExpr ){ 68038b4149cSdrh case OE_Rollback: zType = "rollback"; break; 68138b4149cSdrh case OE_Abort: zType = "abort"; break; 68238b4149cSdrh case OE_Fail: zType = "fail"; break; 68338b4149cSdrh case OE_Ignore: zType = "ignore"; break; 68438b4149cSdrh } 68538b4149cSdrh sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); 68638b4149cSdrh break; 68738b4149cSdrh } 68838b4149cSdrh #endif 689c84a4020Sdrh case TK_MATCH: { 690c84a4020Sdrh sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", 691c84a4020Sdrh pExpr->iTable, pExpr->iColumn, zFlgs); 692c84a4020Sdrh sqlite3TreeViewExpr(pView, pExpr->pRight, 0); 693c84a4020Sdrh break; 694c84a4020Sdrh } 695db97e562Sdrh case TK_VECTOR: { 696269d322dSdrh char *z = sqlite3_mprintf("VECTOR%s",zFlgs); 697269d322dSdrh sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); 698269d322dSdrh sqlite3_free(z); 699db97e562Sdrh break; 700db97e562Sdrh } 70148cb3a76Sdrh case TK_SELECT_COLUMN: { 702*e46292a9Sdrh sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s", 703*e46292a9Sdrh pExpr->iColumn, pExpr->iTable-1, 704*e46292a9Sdrh pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : ""); 70548cb3a76Sdrh sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); 70648cb3a76Sdrh break; 70748cb3a76Sdrh } 70831d6fd55Sdrh case TK_IF_NULL_ROW: { 70931d6fd55Sdrh sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable); 71031d6fd55Sdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); 71131d6fd55Sdrh break; 71231d6fd55Sdrh } 713bf7f3a00Sdrh case TK_ERROR: { 714bf7f3a00Sdrh Expr tmp; 715bf7f3a00Sdrh sqlite3TreeViewLine(pView, "ERROR"); 716bf7f3a00Sdrh tmp = *pExpr; 717bf7f3a00Sdrh tmp.op = pExpr->op2; 718bf7f3a00Sdrh sqlite3TreeViewExpr(pView, &tmp, 0); 719bf7f3a00Sdrh break; 720bf7f3a00Sdrh } 7214a4e02bcSdrh case TK_ROW: { 7224a4e02bcSdrh if( pExpr->iColumn<=0 ){ 7234a4e02bcSdrh sqlite3TreeViewLine(pView, "First FROM table rowid"); 7244a4e02bcSdrh }else{ 7254a4e02bcSdrh sqlite3TreeViewLine(pView, "First FROM table column %d", 7264a4e02bcSdrh pExpr->iColumn-1); 7274a4e02bcSdrh } 7284a4e02bcSdrh break; 7294a4e02bcSdrh } 73038b4149cSdrh default: { 73138b4149cSdrh sqlite3TreeViewLine(pView, "op=%d", pExpr->op); 73238b4149cSdrh break; 73338b4149cSdrh } 73438b4149cSdrh } 73538b4149cSdrh if( zBinOp ){ 736b3d903ebSdrh sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); 73738b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); 73838b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pRight, 0); 73938b4149cSdrh }else if( zUniOp ){ 740b3d903ebSdrh sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); 74138b4149cSdrh sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); 74238b4149cSdrh } 74338b4149cSdrh sqlite3TreeViewPop(pView); 74438b4149cSdrh } 74538b4149cSdrh 746db97e562Sdrh 74738b4149cSdrh /* 74838b4149cSdrh ** Generate a human-readable explanation of an expression list. 74938b4149cSdrh */ 750db97e562Sdrh void sqlite3TreeViewBareExprList( 75138b4149cSdrh TreeView *pView, 75238b4149cSdrh const ExprList *pList, 75338b4149cSdrh const char *zLabel 75438b4149cSdrh ){ 75538b4149cSdrh if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; 75638b4149cSdrh if( pList==0 ){ 75738b4149cSdrh sqlite3TreeViewLine(pView, "%s (empty)", zLabel); 75838b4149cSdrh }else{ 759db97e562Sdrh int i; 76038b4149cSdrh sqlite3TreeViewLine(pView, "%s", zLabel); 76138b4149cSdrh for(i=0; i<pList->nExpr; i++){ 7625579d59fSdrh int j = pList->a[i].u.x.iOrderByCol; 76341cee668Sdrh char *zName = pList->a[i].zEName; 764fbe07539Sdrh int moreToFollow = i<pList->nExpr - 1; 765e1f49b88Sdrh if( pList->a[i].eEName!=ENAME_NAME ) zName = 0; 7665a699a01Sdrh if( j || zName ){ 767fbe07539Sdrh sqlite3TreeViewPush(pView, moreToFollow); 768fbe07539Sdrh moreToFollow = 0; 769fbe07539Sdrh sqlite3TreeViewLine(pView, 0); 7705a699a01Sdrh if( zName ){ 771fbe07539Sdrh fprintf(stdout, "AS %s ", zName); 7725a699a01Sdrh } 7735a699a01Sdrh if( j ){ 774fbe07539Sdrh fprintf(stdout, "iOrderByCol=%d", j); 7755579d59fSdrh } 776fbe07539Sdrh fprintf(stdout, "\n"); 777fbe07539Sdrh fflush(stdout); 778fbe07539Sdrh } 779fbe07539Sdrh sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); 7805a699a01Sdrh if( j || zName ){ 7815a699a01Sdrh sqlite3TreeViewPop(pView); 7825a699a01Sdrh } 78338b4149cSdrh } 78438b4149cSdrh } 785db97e562Sdrh } 786db97e562Sdrh void sqlite3TreeViewExprList( 787db97e562Sdrh TreeView *pView, 788db97e562Sdrh const ExprList *pList, 789db97e562Sdrh u8 moreToFollow, 790db97e562Sdrh const char *zLabel 791db97e562Sdrh ){ 792db97e562Sdrh pView = sqlite3TreeViewPush(pView, moreToFollow); 793db97e562Sdrh sqlite3TreeViewBareExprList(pView, pList, zLabel); 79438b4149cSdrh sqlite3TreeViewPop(pView); 79538b4149cSdrh } 79638b4149cSdrh 79738b4149cSdrh #endif /* SQLITE_DEBUG */ 798