xref: /sqlite-3.40.0/src/treeview.c (revision e46292a9)
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