1 | /* |
2 | ** 2015-06-08 |
3 | ** |
4 | ** The author disclaims copyright to this source code. In place of |
5 | ** a legal notice, here is a blessing: |
6 | ** |
7 | ** May you do good and not evil. |
8 | ** May you find forgiveness for yourself and forgive others. |
9 | ** May you share freely, never taking more than you give. |
10 | ** |
11 | ************************************************************************* |
12 | ** |
13 | ** This file contains C code to implement the TreeView debugging routines. |
14 | ** These routines print a parse tree to standard output for debugging and |
15 | ** analysis. |
16 | ** |
17 | ** The interfaces in this file is only available when compiling |
18 | ** with SQLITE_DEBUG. |
19 | */ |
20 | #include "sqliteInt.h" |
21 | #ifdef SQLITE_DEBUG |
22 | |
23 | /* |
24 | ** Add a new subitem to the tree. The moreToFollow flag indicates that this |
25 | ** is not the last item in the tree. |
26 | */ |
27 | static void sqlite3TreeViewPush(TreeView **pp, u8 moreToFollow){ |
28 | TreeView *p = *pp; |
29 | if( p==0 ){ |
30 | *pp = p = sqlite3_malloc64( sizeof(*p) ); |
31 | if( p==0 ) return; |
32 | memset(p, 0, sizeof(*p)); |
33 | }else{ |
34 | p->iLevel++; |
35 | } |
36 | assert( moreToFollow==0 || moreToFollow==1 ); |
37 | if( p->iLevel<(int)sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; |
38 | } |
39 | |
40 | /* |
41 | ** Finished with one layer of the tree |
42 | */ |
43 | static void sqlite3TreeViewPop(TreeView **pp){ |
44 | TreeView *p = *pp; |
45 | if( p==0 ) return; |
46 | p->iLevel--; |
47 | if( p->iLevel<0 ){ |
48 | sqlite3_free(p); |
49 | *pp = 0; |
50 | } |
51 | } |
52 | |
53 | /* |
54 | ** Generate a single line of output for the tree, with a prefix that contains |
55 | ** all the appropriate tree lines |
56 | */ |
57 | void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ |
58 | va_list ap; |
59 | int i; |
60 | StrAccum acc; |
61 | char zBuf[1000]; |
62 | sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); |
63 | if( p ){ |
64 | for(i=0; i<p->iLevel && i<(int)sizeof(p->bLine)-1; i++){ |
65 | sqlite3_str_append(&acc, p->bLine[i] ? "| " : " " , 4); |
66 | } |
67 | sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- " , 4); |
68 | } |
69 | if( zFormat!=0 ){ |
70 | va_start(ap, zFormat); |
71 | sqlite3_str_vappendf(&acc, zFormat, ap); |
72 | va_end(ap); |
73 | assert( acc.nChar>0 || acc.accError ); |
74 | sqlite3_str_append(&acc, "\n" , 1); |
75 | } |
76 | sqlite3StrAccumFinish(&acc); |
77 | fprintf(stdout,"%s" , zBuf); |
78 | fflush(stdout); |
79 | } |
80 | |
81 | /* |
82 | ** Shorthand for starting a new tree item that consists of a single label |
83 | */ |
84 | static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ |
85 | sqlite3TreeViewPush(&p, moreFollows); |
86 | sqlite3TreeViewLine(p, "%s" , zLabel); |
87 | } |
88 | |
89 | /* |
90 | ** Show a list of Column objects in tree format. |
91 | */ |
92 | void sqlite3TreeViewColumnList( |
93 | TreeView *pView, |
94 | const Column *aCol, |
95 | int nCol, |
96 | u8 moreToFollow |
97 | ){ |
98 | int i; |
99 | sqlite3TreeViewPush(&pView, moreToFollow); |
100 | sqlite3TreeViewLine(pView, "COLUMNS" ); |
101 | for(i=0; i<nCol; i++){ |
102 | u16 flg = aCol[i].colFlags; |
103 | int colMoreToFollow = i<(nCol - 1); |
104 | sqlite3TreeViewPush(&pView, colMoreToFollow); |
105 | sqlite3TreeViewLine(pView, 0); |
106 | printf(" %s" , aCol[i].zCnName); |
107 | switch( aCol[i].eCType ){ |
108 | case COLTYPE_ANY: printf(" ANY" ); break; |
109 | case COLTYPE_BLOB: printf(" BLOB" ); break; |
110 | case COLTYPE_INT: printf(" INT" ); break; |
111 | case COLTYPE_INTEGER: printf(" INTEGER" ); break; |
112 | case COLTYPE_REAL: printf(" REAL" ); break; |
113 | case COLTYPE_TEXT: printf(" TEXT" ); break; |
114 | case COLTYPE_CUSTOM: { |
115 | if( flg & COLFLAG_HASTYPE ){ |
116 | const char *z = aCol[i].zCnName; |
117 | z += strlen(z)+1; |
118 | printf(" X-%s" , z); |
119 | break; |
120 | } |
121 | } |
122 | } |
123 | if( flg & COLFLAG_PRIMKEY ) printf(" PRIMARY KEY" ); |
124 | if( flg & COLFLAG_HIDDEN ) printf(" HIDDEN" ); |
125 | #ifdef COLFLAG_NOEXPAND |
126 | if( flg & COLFLAG_NOEXPAND ) printf(" NO-EXPAND" ); |
127 | #endif |
128 | if( flg ) printf(" flags=%04x" , flg); |
129 | printf("\n" ); |
130 | fflush(stdout); |
131 | sqlite3TreeViewPop(&pView); |
132 | } |
133 | sqlite3TreeViewPop(&pView); |
134 | } |
135 | |
136 | /* |
137 | ** Generate a human-readable description of a WITH clause. |
138 | */ |
139 | void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){ |
140 | int i; |
141 | if( pWith==0 ) return; |
142 | if( pWith->nCte==0 ) return; |
143 | if( pWith->pOuter ){ |
144 | sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)" ,pWith,pWith->pOuter); |
145 | }else{ |
146 | sqlite3TreeViewLine(pView, "WITH (0x%p)" , pWith); |
147 | } |
148 | if( pWith->nCte>0 ){ |
149 | sqlite3TreeViewPush(&pView, moreToFollow); |
150 | for(i=0; i<pWith->nCte; i++){ |
151 | StrAccum x; |
152 | char zLine[1000]; |
153 | const struct Cte *pCte = &pWith->a[i]; |
154 | sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); |
155 | sqlite3_str_appendf(&x, "%s" , pCte->zName); |
156 | if( pCte->pCols && pCte->pCols->nExpr>0 ){ |
157 | char cSep = '('; |
158 | int j; |
159 | for(j=0; j<pCte->pCols->nExpr; j++){ |
160 | sqlite3_str_appendf(&x, "%c%s" , cSep, pCte->pCols->a[j].zEName); |
161 | cSep = ','; |
162 | } |
163 | sqlite3_str_appendf(&x, ")" ); |
164 | } |
165 | if( pCte->eM10d!=M10d_Any ){ |
166 | sqlite3_str_appendf(&x, " %sMATERIALIZED" , |
167 | pCte->eM10d==M10d_No ? "NOT " : "" ); |
168 | } |
169 | if( pCte->pUse ){ |
170 | sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)" , pCte->pUse, |
171 | pCte->pUse->nUse); |
172 | } |
173 | sqlite3StrAccumFinish(&x); |
174 | sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); |
175 | sqlite3TreeViewSelect(pView, pCte->pSelect, 0); |
176 | sqlite3TreeViewPop(&pView); |
177 | } |
178 | sqlite3TreeViewPop(&pView); |
179 | } |
180 | } |
181 | |
182 | /* |
183 | ** Generate a human-readable description of a SrcList object. |
184 | */ |
185 | void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ |
186 | int i; |
187 | if( pSrc==0 ) return; |
188 | for(i=0; i<pSrc->nSrc; i++){ |
189 | const SrcItem *pItem = &pSrc->a[i]; |
190 | StrAccum x; |
191 | int n = 0; |
192 | char zLine[1000]; |
193 | sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); |
194 | x.printfFlags |= SQLITE_PRINTF_INTERNAL; |
195 | sqlite3_str_appendf(&x, "{%d:*} %!S" , pItem->iCursor, pItem); |
196 | if( pItem->pTab ){ |
197 | sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx" , |
198 | pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); |
199 | } |
200 | if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){ |
201 | sqlite3_str_appendf(&x, " FULL-OUTER-JOIN" ); |
202 | }else if( pItem->fg.jointype & JT_LEFT ){ |
203 | sqlite3_str_appendf(&x, " LEFT-JOIN" ); |
204 | }else if( pItem->fg.jointype & JT_RIGHT ){ |
205 | sqlite3_str_appendf(&x, " RIGHT-JOIN" ); |
206 | }else if( pItem->fg.jointype & JT_CROSS ){ |
207 | sqlite3_str_appendf(&x, " CROSS-JOIN" ); |
208 | } |
209 | if( pItem->fg.jointype & JT_LTORJ ){ |
210 | sqlite3_str_appendf(&x, " LTORJ" ); |
211 | } |
212 | if( pItem->fg.fromDDL ){ |
213 | sqlite3_str_appendf(&x, " DDL" ); |
214 | } |
215 | if( pItem->fg.isCte ){ |
216 | sqlite3_str_appendf(&x, " CteUse=0x%p" , pItem->u2.pCteUse); |
217 | } |
218 | if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){ |
219 | sqlite3_str_appendf(&x, " ON" ); |
220 | } |
221 | sqlite3StrAccumFinish(&x); |
222 | sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); |
223 | n = 0; |
224 | if( pItem->pSelect ) n++; |
225 | if( pItem->fg.isTabFunc ) n++; |
226 | if( pItem->fg.isUsing ) n++; |
227 | if( pItem->fg.isUsing ){ |
228 | sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING" ); |
229 | } |
230 | if( pItem->pSelect ){ |
231 | if( pItem->pTab ){ |
232 | Table *pTab = pItem->pTab; |
233 | sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); |
234 | } |
235 | assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); |
236 | sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); |
237 | } |
238 | if( pItem->fg.isTabFunc ){ |
239 | sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:" ); |
240 | } |
241 | sqlite3TreeViewPop(&pView); |
242 | } |
243 | } |
244 | |
245 | /* |
246 | ** Generate a human-readable description of a Select object. |
247 | */ |
248 | void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ |
249 | int n = 0; |
250 | int cnt = 0; |
251 | if( p==0 ){ |
252 | sqlite3TreeViewLine(pView, "nil-SELECT" ); |
253 | return; |
254 | } |
255 | sqlite3TreeViewPush(&pView, moreToFollow); |
256 | if( p->pWith ){ |
257 | sqlite3TreeViewWith(pView, p->pWith, 1); |
258 | cnt = 1; |
259 | sqlite3TreeViewPush(&pView, 1); |
260 | } |
261 | do{ |
262 | if( p->selFlags & SF_WhereBegin ){ |
263 | sqlite3TreeViewLine(pView, "sqlite3WhereBegin()" ); |
264 | }else{ |
265 | sqlite3TreeViewLine(pView, |
266 | "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d" , |
267 | ((p->selFlags & SF_Distinct) ? " DISTINCT" : "" ), |
268 | ((p->selFlags & SF_Aggregate) ? " agg_flag" : "" ), |
269 | p->selId, p, p->selFlags, |
270 | (int)p->nSelectRow |
271 | ); |
272 | } |
273 | if( cnt++ ) sqlite3TreeViewPop(&pView); |
274 | if( p->pPrior ){ |
275 | n = 1000; |
276 | }else{ |
277 | n = 0; |
278 | if( p->pSrc && p->pSrc->nSrc ) n++; |
279 | if( p->pWhere ) n++; |
280 | if( p->pGroupBy ) n++; |
281 | if( p->pHaving ) n++; |
282 | if( p->pOrderBy ) n++; |
283 | if( p->pLimit ) n++; |
284 | #ifndef SQLITE_OMIT_WINDOWFUNC |
285 | if( p->pWin ) n++; |
286 | if( p->pWinDefn ) n++; |
287 | #endif |
288 | } |
289 | if( p->pEList ){ |
290 | sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set" ); |
291 | } |
292 | n--; |
293 | #ifndef SQLITE_OMIT_WINDOWFUNC |
294 | if( p->pWin ){ |
295 | Window *pX; |
296 | sqlite3TreeViewPush(&pView, (n--)>0); |
297 | sqlite3TreeViewLine(pView, "window-functions" ); |
298 | for(pX=p->pWin; pX; pX=pX->pNextWin){ |
299 | sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); |
300 | } |
301 | sqlite3TreeViewPop(&pView); |
302 | } |
303 | #endif |
304 | if( p->pSrc && p->pSrc->nSrc ){ |
305 | sqlite3TreeViewPush(&pView, (n--)>0); |
306 | sqlite3TreeViewLine(pView, "FROM" ); |
307 | sqlite3TreeViewSrcList(pView, p->pSrc); |
308 | sqlite3TreeViewPop(&pView); |
309 | } |
310 | if( p->pWhere ){ |
311 | sqlite3TreeViewItem(pView, "WHERE" , (n--)>0); |
312 | sqlite3TreeViewExpr(pView, p->pWhere, 0); |
313 | sqlite3TreeViewPop(&pView); |
314 | } |
315 | if( p->pGroupBy ){ |
316 | sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY" ); |
317 | } |
318 | if( p->pHaving ){ |
319 | sqlite3TreeViewItem(pView, "HAVING" , (n--)>0); |
320 | sqlite3TreeViewExpr(pView, p->pHaving, 0); |
321 | sqlite3TreeViewPop(&pView); |
322 | } |
323 | #ifndef SQLITE_OMIT_WINDOWFUNC |
324 | if( p->pWinDefn ){ |
325 | Window *pX; |
326 | sqlite3TreeViewItem(pView, "WINDOW" , (n--)>0); |
327 | for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ |
328 | sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); |
329 | } |
330 | sqlite3TreeViewPop(&pView); |
331 | } |
332 | #endif |
333 | if( p->pOrderBy ){ |
334 | sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY" ); |
335 | } |
336 | if( p->pLimit ){ |
337 | sqlite3TreeViewItem(pView, "LIMIT" , (n--)>0); |
338 | sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0); |
339 | if( p->pLimit->pRight ){ |
340 | sqlite3TreeViewItem(pView, "OFFSET" , (n--)>0); |
341 | sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); |
342 | sqlite3TreeViewPop(&pView); |
343 | } |
344 | sqlite3TreeViewPop(&pView); |
345 | } |
346 | if( p->pPrior ){ |
347 | const char *zOp = "UNION" ; |
348 | switch( p->op ){ |
349 | case TK_ALL: zOp = "UNION ALL" ; break; |
350 | case TK_INTERSECT: zOp = "INTERSECT" ; break; |
351 | case TK_EXCEPT: zOp = "EXCEPT" ; break; |
352 | } |
353 | sqlite3TreeViewItem(pView, zOp, 1); |
354 | } |
355 | p = p->pPrior; |
356 | }while( p!=0 ); |
357 | sqlite3TreeViewPop(&pView); |
358 | } |
359 | |
360 | #ifndef SQLITE_OMIT_WINDOWFUNC |
361 | /* |
362 | ** Generate a description of starting or stopping bounds |
363 | */ |
364 | void sqlite3TreeViewBound( |
365 | TreeView *pView, /* View context */ |
366 | u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */ |
367 | Expr *pExpr, /* Value for PRECEDING or FOLLOWING */ |
368 | u8 moreToFollow /* True if more to follow */ |
369 | ){ |
370 | switch( eBound ){ |
371 | case TK_UNBOUNDED: { |
372 | sqlite3TreeViewItem(pView, "UNBOUNDED" , moreToFollow); |
373 | sqlite3TreeViewPop(&pView); |
374 | break; |
375 | } |
376 | case TK_CURRENT: { |
377 | sqlite3TreeViewItem(pView, "CURRENT" , moreToFollow); |
378 | sqlite3TreeViewPop(&pView); |
379 | break; |
380 | } |
381 | case TK_PRECEDING: { |
382 | sqlite3TreeViewItem(pView, "PRECEDING" , moreToFollow); |
383 | sqlite3TreeViewExpr(pView, pExpr, 0); |
384 | sqlite3TreeViewPop(&pView); |
385 | break; |
386 | } |
387 | case TK_FOLLOWING: { |
388 | sqlite3TreeViewItem(pView, "FOLLOWING" , moreToFollow); |
389 | sqlite3TreeViewExpr(pView, pExpr, 0); |
390 | sqlite3TreeViewPop(&pView); |
391 | break; |
392 | } |
393 | } |
394 | } |
395 | #endif /* SQLITE_OMIT_WINDOWFUNC */ |
396 | |
397 | #ifndef SQLITE_OMIT_WINDOWFUNC |
398 | /* |
399 | ** Generate a human-readable explanation for a Window object |
400 | */ |
401 | void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ |
402 | int nElement = 0; |
403 | if( pWin==0 ) return; |
404 | if( pWin->pFilter ){ |
405 | sqlite3TreeViewItem(pView, "FILTER" , 1); |
406 | sqlite3TreeViewExpr(pView, pWin->pFilter, 0); |
407 | sqlite3TreeViewPop(&pView); |
408 | } |
409 | sqlite3TreeViewPush(&pView, more); |
410 | if( pWin->zName ){ |
411 | sqlite3TreeViewLine(pView, "OVER %s (%p)" , pWin->zName, pWin); |
412 | }else{ |
413 | sqlite3TreeViewLine(pView, "OVER (%p)" , pWin); |
414 | } |
415 | if( pWin->zBase ) nElement++; |
416 | if( pWin->pOrderBy ) nElement++; |
417 | if( pWin->eFrmType ) nElement++; |
418 | if( pWin->eExclude ) nElement++; |
419 | if( pWin->zBase ){ |
420 | sqlite3TreeViewPush(&pView, (--nElement)>0); |
421 | sqlite3TreeViewLine(pView, "window: %s" , pWin->zBase); |
422 | sqlite3TreeViewPop(&pView); |
423 | } |
424 | if( pWin->pPartition ){ |
425 | sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY" ); |
426 | } |
427 | if( pWin->pOrderBy ){ |
428 | sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY" ); |
429 | } |
430 | if( pWin->eFrmType ){ |
431 | char zBuf[30]; |
432 | const char *zFrmType = "ROWS" ; |
433 | if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE" ; |
434 | if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS" ; |
435 | sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s" ,zFrmType, |
436 | pWin->bImplicitFrame ? " (implied)" : "" ); |
437 | sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); |
438 | sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); |
439 | sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); |
440 | sqlite3TreeViewPop(&pView); |
441 | } |
442 | if( pWin->eExclude ){ |
443 | char zBuf[30]; |
444 | const char *zExclude; |
445 | switch( pWin->eExclude ){ |
446 | case TK_NO: zExclude = "NO OTHERS" ; break; |
447 | case TK_CURRENT: zExclude = "CURRENT ROW" ; break; |
448 | case TK_GROUP: zExclude = "GROUP" ; break; |
449 | case TK_TIES: zExclude = "TIES" ; break; |
450 | default: |
451 | sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)" , pWin->eExclude); |
452 | zExclude = zBuf; |
453 | break; |
454 | } |
455 | sqlite3TreeViewPush(&pView, 0); |
456 | sqlite3TreeViewLine(pView, "EXCLUDE %s" , zExclude); |
457 | sqlite3TreeViewPop(&pView); |
458 | } |
459 | sqlite3TreeViewPop(&pView); |
460 | } |
461 | #endif /* SQLITE_OMIT_WINDOWFUNC */ |
462 | |
463 | #ifndef SQLITE_OMIT_WINDOWFUNC |
464 | /* |
465 | ** Generate a human-readable explanation for a Window Function object |
466 | */ |
467 | void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ |
468 | if( pWin==0 ) return; |
469 | sqlite3TreeViewPush(&pView, more); |
470 | sqlite3TreeViewLine(pView, "WINFUNC %s(%d)" , |
471 | pWin->pWFunc->zName, pWin->pWFunc->nArg); |
472 | sqlite3TreeViewWindow(pView, pWin, 0); |
473 | sqlite3TreeViewPop(&pView); |
474 | } |
475 | #endif /* SQLITE_OMIT_WINDOWFUNC */ |
476 | |
477 | /* |
478 | ** Generate a human-readable explanation of an expression tree. |
479 | */ |
480 | void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ |
481 | const char *zBinOp = 0; /* Binary operator */ |
482 | const char *zUniOp = 0; /* Unary operator */ |
483 | char zFlgs[200]; |
484 | sqlite3TreeViewPush(&pView, moreToFollow); |
485 | if( pExpr==0 ){ |
486 | sqlite3TreeViewLine(pView, "nil" ); |
487 | sqlite3TreeViewPop(&pView); |
488 | return; |
489 | } |
490 | if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){ |
491 | StrAccum x; |
492 | sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); |
493 | sqlite3_str_appendf(&x, " fg.af=%x.%c" , |
494 | pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); |
495 | if( ExprHasProperty(pExpr, EP_OuterON) ){ |
496 | sqlite3_str_appendf(&x, " outer.iJoin=%d" , pExpr->w.iJoin); |
497 | } |
498 | if( ExprHasProperty(pExpr, EP_InnerON) ){ |
499 | sqlite3_str_appendf(&x, " inner.iJoin=%d" , pExpr->w.iJoin); |
500 | } |
501 | if( ExprHasProperty(pExpr, EP_FromDDL) ){ |
502 | sqlite3_str_appendf(&x, " DDL" ); |
503 | } |
504 | if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ |
505 | sqlite3_str_appendf(&x, " IMMUTABLE" ); |
506 | } |
507 | sqlite3StrAccumFinish(&x); |
508 | }else{ |
509 | zFlgs[0] = 0; |
510 | } |
511 | switch( pExpr->op ){ |
512 | case TK_AGG_COLUMN: { |
513 | sqlite3TreeViewLine(pView, "AGG{%d:%d}%s" , |
514 | pExpr->iTable, pExpr->iColumn, zFlgs); |
515 | break; |
516 | } |
517 | case TK_COLUMN: { |
518 | if( pExpr->iTable<0 ){ |
519 | /* This only happens when coding check constraints */ |
520 | char zOp2[16]; |
521 | if( pExpr->op2 ){ |
522 | sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x" ,pExpr->op2); |
523 | }else{ |
524 | zOp2[0] = 0; |
525 | } |
526 | sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s" , |
527 | pExpr->iColumn, zFlgs, zOp2); |
528 | }else{ |
529 | assert( ExprUseYTab(pExpr) ); |
530 | sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s" , |
531 | pExpr->iTable, pExpr->iColumn, |
532 | pExpr->y.pTab, zFlgs); |
533 | } |
534 | if( ExprHasProperty(pExpr, EP_FixedCol) ){ |
535 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
536 | } |
537 | break; |
538 | } |
539 | case TK_INTEGER: { |
540 | if( pExpr->flags & EP_IntValue ){ |
541 | sqlite3TreeViewLine(pView, "%d" , pExpr->u.iValue); |
542 | }else{ |
543 | sqlite3TreeViewLine(pView, "%s" , pExpr->u.zToken); |
544 | } |
545 | break; |
546 | } |
547 | #ifndef SQLITE_OMIT_FLOATING_POINT |
548 | case TK_FLOAT: { |
549 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
550 | sqlite3TreeViewLine(pView,"%s" , pExpr->u.zToken); |
551 | break; |
552 | } |
553 | #endif |
554 | case TK_STRING: { |
555 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
556 | sqlite3TreeViewLine(pView,"%Q" , pExpr->u.zToken); |
557 | break; |
558 | } |
559 | case TK_NULL: { |
560 | sqlite3TreeViewLine(pView,"NULL" ); |
561 | break; |
562 | } |
563 | case TK_TRUEFALSE: { |
564 | sqlite3TreeViewLine(pView,"%s%s" , |
565 | sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE" , zFlgs); |
566 | break; |
567 | } |
568 | #ifndef SQLITE_OMIT_BLOB_LITERAL |
569 | case TK_BLOB: { |
570 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
571 | sqlite3TreeViewLine(pView,"%s" , pExpr->u.zToken); |
572 | break; |
573 | } |
574 | #endif |
575 | case TK_VARIABLE: { |
576 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
577 | sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)" , |
578 | pExpr->u.zToken, pExpr->iColumn); |
579 | break; |
580 | } |
581 | case TK_REGISTER: { |
582 | sqlite3TreeViewLine(pView,"REGISTER(%d)" , pExpr->iTable); |
583 | break; |
584 | } |
585 | case TK_ID: { |
586 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
587 | sqlite3TreeViewLine(pView,"ID \"%w\"" , pExpr->u.zToken); |
588 | break; |
589 | } |
590 | #ifndef SQLITE_OMIT_CAST |
591 | case TK_CAST: { |
592 | /* Expressions of the form: CAST(pLeft AS token) */ |
593 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
594 | sqlite3TreeViewLine(pView,"CAST %Q" , pExpr->u.zToken); |
595 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
596 | break; |
597 | } |
598 | #endif /* SQLITE_OMIT_CAST */ |
599 | case TK_LT: zBinOp = "LT" ; break; |
600 | case TK_LE: zBinOp = "LE" ; break; |
601 | case TK_GT: zBinOp = "GT" ; break; |
602 | case TK_GE: zBinOp = "GE" ; break; |
603 | case TK_NE: zBinOp = "NE" ; break; |
604 | case TK_EQ: zBinOp = "EQ" ; break; |
605 | case TK_IS: zBinOp = "IS" ; break; |
606 | case TK_ISNOT: zBinOp = "ISNOT" ; break; |
607 | case TK_AND: zBinOp = "AND" ; break; |
608 | case TK_OR: zBinOp = "OR" ; break; |
609 | case TK_PLUS: zBinOp = "ADD" ; break; |
610 | case TK_STAR: zBinOp = "MUL" ; break; |
611 | case TK_MINUS: zBinOp = "SUB" ; break; |
612 | case TK_REM: zBinOp = "REM" ; break; |
613 | case TK_BITAND: zBinOp = "BITAND" ; break; |
614 | case TK_BITOR: zBinOp = "BITOR" ; break; |
615 | case TK_SLASH: zBinOp = "DIV" ; break; |
616 | case TK_LSHIFT: zBinOp = "LSHIFT" ; break; |
617 | case TK_RSHIFT: zBinOp = "RSHIFT" ; break; |
618 | case TK_CONCAT: zBinOp = "CONCAT" ; break; |
619 | case TK_DOT: zBinOp = "DOT" ; break; |
620 | case TK_LIMIT: zBinOp = "LIMIT" ; break; |
621 | |
622 | case TK_UMINUS: zUniOp = "UMINUS" ; break; |
623 | case TK_UPLUS: zUniOp = "UPLUS" ; break; |
624 | case TK_BITNOT: zUniOp = "BITNOT" ; break; |
625 | case TK_NOT: zUniOp = "NOT" ; break; |
626 | case TK_ISNULL: zUniOp = "ISNULL" ; break; |
627 | case TK_NOTNULL: zUniOp = "NOTNULL" ; break; |
628 | |
629 | case TK_TRUTH: { |
630 | int x; |
631 | const char *azOp[] = { |
632 | "IS-FALSE" , "IS-TRUE" , "IS-NOT-FALSE" , "IS-NOT-TRUE" |
633 | }; |
634 | assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); |
635 | assert( pExpr->pRight ); |
636 | assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); |
637 | x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); |
638 | zUniOp = azOp[x]; |
639 | break; |
640 | } |
641 | |
642 | case TK_SPAN: { |
643 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
644 | sqlite3TreeViewLine(pView, "SPAN %Q" , pExpr->u.zToken); |
645 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
646 | break; |
647 | } |
648 | |
649 | case TK_COLLATE: { |
650 | /* COLLATE operators without the EP_Collate flag are intended to |
651 | ** emulate collation associated with a table column. These show |
652 | ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE |
653 | ** operators that appear in the original SQL always have the |
654 | ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ |
655 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
656 | sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s" , |
657 | !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "" , |
658 | pExpr->u.zToken, zFlgs); |
659 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
660 | break; |
661 | } |
662 | |
663 | case TK_AGG_FUNCTION: |
664 | case TK_FUNCTION: { |
665 | ExprList *pFarg; /* List of function arguments */ |
666 | Window *pWin; |
667 | if( ExprHasProperty(pExpr, EP_TokenOnly) ){ |
668 | pFarg = 0; |
669 | pWin = 0; |
670 | }else{ |
671 | assert( ExprUseXList(pExpr) ); |
672 | pFarg = pExpr->x.pList; |
673 | #ifndef SQLITE_OMIT_WINDOWFUNC |
674 | pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; |
675 | #else |
676 | pWin = 0; |
677 | #endif |
678 | } |
679 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
680 | if( pExpr->op==TK_AGG_FUNCTION ){ |
681 | sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p" , |
682 | pExpr->op2, pExpr->u.zToken, zFlgs, |
683 | pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0, |
684 | pExpr->iAgg, pExpr->pAggInfo); |
685 | }else if( pExpr->op2!=0 ){ |
686 | const char *zOp2; |
687 | char zBuf[8]; |
688 | sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x" ,pExpr->op2); |
689 | zOp2 = zBuf; |
690 | if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck" ; |
691 | if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr" ; |
692 | if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx" ; |
693 | if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol" ; |
694 | sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s" , |
695 | pExpr->u.zToken, zFlgs, zOp2); |
696 | }else{ |
697 | sqlite3TreeViewLine(pView, "FUNCTION %Q%s" , pExpr->u.zToken, zFlgs); |
698 | } |
699 | if( pFarg ){ |
700 | sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); |
701 | } |
702 | #ifndef SQLITE_OMIT_WINDOWFUNC |
703 | if( pWin ){ |
704 | sqlite3TreeViewWindow(pView, pWin, 0); |
705 | } |
706 | #endif |
707 | break; |
708 | } |
709 | #ifndef SQLITE_OMIT_SUBQUERY |
710 | case TK_EXISTS: { |
711 | assert( ExprUseXSelect(pExpr) ); |
712 | sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x" , pExpr->flags); |
713 | sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); |
714 | break; |
715 | } |
716 | case TK_SELECT: { |
717 | assert( ExprUseXSelect(pExpr) ); |
718 | sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x" , pExpr->flags); |
719 | sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); |
720 | break; |
721 | } |
722 | case TK_IN: { |
723 | sqlite3_str *pStr = sqlite3_str_new(0); |
724 | char *z; |
725 | sqlite3_str_appendf(pStr, "IN flags=0x%x" , pExpr->flags); |
726 | if( pExpr->iTable ) sqlite3_str_appendf(pStr, " iTable=%d" ,pExpr->iTable); |
727 | if( ExprHasProperty(pExpr, EP_Subrtn) ){ |
728 | sqlite3_str_appendf(pStr, " subrtn(%d,%d)" , |
729 | pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); |
730 | } |
731 | z = sqlite3_str_finish(pStr); |
732 | sqlite3TreeViewLine(pView, z); |
733 | sqlite3_free(z); |
734 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); |
735 | if( ExprUseXSelect(pExpr) ){ |
736 | sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); |
737 | }else{ |
738 | sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); |
739 | } |
740 | break; |
741 | } |
742 | #endif /* SQLITE_OMIT_SUBQUERY */ |
743 | |
744 | /* |
745 | ** x BETWEEN y AND z |
746 | ** |
747 | ** This is equivalent to |
748 | ** |
749 | ** x>=y AND x<=z |
750 | ** |
751 | ** X is stored in pExpr->pLeft. |
752 | ** Y is stored in pExpr->pList->a[0].pExpr. |
753 | ** Z is stored in pExpr->pList->a[1].pExpr. |
754 | */ |
755 | case TK_BETWEEN: { |
756 | const Expr *pX, *pY, *pZ; |
757 | pX = pExpr->pLeft; |
758 | assert( ExprUseXList(pExpr) ); |
759 | assert( pExpr->x.pList->nExpr==2 ); |
760 | pY = pExpr->x.pList->a[0].pExpr; |
761 | pZ = pExpr->x.pList->a[1].pExpr; |
762 | sqlite3TreeViewLine(pView, "BETWEEN" ); |
763 | sqlite3TreeViewExpr(pView, pX, 1); |
764 | sqlite3TreeViewExpr(pView, pY, 1); |
765 | sqlite3TreeViewExpr(pView, pZ, 0); |
766 | break; |
767 | } |
768 | case TK_TRIGGER: { |
769 | /* If the opcode is TK_TRIGGER, then the expression is a reference |
770 | ** to a column in the new.* or old.* pseudo-tables available to |
771 | ** trigger programs. In this case Expr.iTable is set to 1 for the |
772 | ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn |
773 | ** is set to the column of the pseudo-table to read, or to -1 to |
774 | ** read the rowid field. |
775 | */ |
776 | sqlite3TreeViewLine(pView, "%s(%d)" , |
777 | pExpr->iTable ? "NEW" : "OLD" , pExpr->iColumn); |
778 | break; |
779 | } |
780 | case TK_CASE: { |
781 | sqlite3TreeViewLine(pView, "CASE" ); |
782 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); |
783 | assert( ExprUseXList(pExpr) ); |
784 | sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); |
785 | break; |
786 | } |
787 | #ifndef SQLITE_OMIT_TRIGGER |
788 | case TK_RAISE: { |
789 | const char *zType = "unk" ; |
790 | switch( pExpr->affExpr ){ |
791 | case OE_Rollback: zType = "rollback" ; break; |
792 | case OE_Abort: zType = "abort" ; break; |
793 | case OE_Fail: zType = "fail" ; break; |
794 | case OE_Ignore: zType = "ignore" ; break; |
795 | } |
796 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
797 | sqlite3TreeViewLine(pView, "RAISE %s(%Q)" , zType, pExpr->u.zToken); |
798 | break; |
799 | } |
800 | #endif |
801 | case TK_MATCH: { |
802 | sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s" , |
803 | pExpr->iTable, pExpr->iColumn, zFlgs); |
804 | sqlite3TreeViewExpr(pView, pExpr->pRight, 0); |
805 | break; |
806 | } |
807 | case TK_VECTOR: { |
808 | char *z = sqlite3_mprintf("VECTOR%s" ,zFlgs); |
809 | assert( ExprUseXList(pExpr) ); |
810 | sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); |
811 | sqlite3_free(z); |
812 | break; |
813 | } |
814 | case TK_SELECT_COLUMN: { |
815 | sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s" , |
816 | pExpr->iColumn, pExpr->iTable-1, |
817 | pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : "" ); |
818 | assert( ExprUseXSelect(pExpr->pLeft) ); |
819 | sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); |
820 | break; |
821 | } |
822 | case TK_IF_NULL_ROW: { |
823 | sqlite3TreeViewLine(pView, "IF-NULL-ROW %d" , pExpr->iTable); |
824 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
825 | break; |
826 | } |
827 | case TK_ERROR: { |
828 | Expr tmp; |
829 | sqlite3TreeViewLine(pView, "ERROR" ); |
830 | tmp = *pExpr; |
831 | tmp.op = pExpr->op2; |
832 | sqlite3TreeViewExpr(pView, &tmp, 0); |
833 | break; |
834 | } |
835 | case TK_ROW: { |
836 | if( pExpr->iColumn<=0 ){ |
837 | sqlite3TreeViewLine(pView, "First FROM table rowid" ); |
838 | }else{ |
839 | sqlite3TreeViewLine(pView, "First FROM table column %d" , |
840 | pExpr->iColumn-1); |
841 | } |
842 | break; |
843 | } |
844 | default: { |
845 | sqlite3TreeViewLine(pView, "op=%d" , pExpr->op); |
846 | break; |
847 | } |
848 | } |
849 | if( zBinOp ){ |
850 | sqlite3TreeViewLine(pView, "%s%s" , zBinOp, zFlgs); |
851 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); |
852 | sqlite3TreeViewExpr(pView, pExpr->pRight, 0); |
853 | }else if( zUniOp ){ |
854 | sqlite3TreeViewLine(pView, "%s%s" , zUniOp, zFlgs); |
855 | sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
856 | } |
857 | sqlite3TreeViewPop(&pView); |
858 | } |
859 | |
860 | |
861 | /* |
862 | ** Generate a human-readable explanation of an expression list. |
863 | */ |
864 | void sqlite3TreeViewBareExprList( |
865 | TreeView *pView, |
866 | const ExprList *pList, |
867 | const char *zLabel |
868 | ){ |
869 | if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST" ; |
870 | if( pList==0 ){ |
871 | sqlite3TreeViewLine(pView, "%s (empty)" , zLabel); |
872 | }else{ |
873 | int i; |
874 | sqlite3TreeViewLine(pView, "%s" , zLabel); |
875 | for(i=0; i<pList->nExpr; i++){ |
876 | int j = pList->a[i].u.x.iOrderByCol; |
877 | char *zName = pList->a[i].zEName; |
878 | int moreToFollow = i<pList->nExpr - 1; |
879 | if( j || zName ){ |
880 | sqlite3TreeViewPush(&pView, moreToFollow); |
881 | moreToFollow = 0; |
882 | sqlite3TreeViewLine(pView, 0); |
883 | if( zName ){ |
884 | switch( pList->a[i].fg.eEName ){ |
885 | default: |
886 | fprintf(stdout, "AS %s " , zName); |
887 | break; |
888 | case ENAME_TAB: |
889 | fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") " , zName); |
890 | if( pList->a[i].fg.bUsed ) fprintf(stdout, "(used) " ); |
891 | if( pList->a[i].fg.bUsingTerm ) fprintf(stdout, "(USING-term) " ); |
892 | if( pList->a[i].fg.bNoExpand ) fprintf(stdout, "(NoExpand) " ); |
893 | break; |
894 | case ENAME_SPAN: |
895 | fprintf(stdout, "SPAN(\"%s\") " , zName); |
896 | break; |
897 | } |
898 | } |
899 | if( j ){ |
900 | fprintf(stdout, "iOrderByCol=%d" , j); |
901 | } |
902 | fprintf(stdout, "\n" ); |
903 | fflush(stdout); |
904 | } |
905 | sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); |
906 | if( j || zName ){ |
907 | sqlite3TreeViewPop(&pView); |
908 | } |
909 | } |
910 | } |
911 | } |
912 | void sqlite3TreeViewExprList( |
913 | TreeView *pView, |
914 | const ExprList *pList, |
915 | u8 moreToFollow, |
916 | const char *zLabel |
917 | ){ |
918 | sqlite3TreeViewPush(&pView, moreToFollow); |
919 | sqlite3TreeViewBareExprList(pView, pList, zLabel); |
920 | sqlite3TreeViewPop(&pView); |
921 | } |
922 | |
923 | /* |
924 | ** Generate a human-readable explanation of an id-list. |
925 | */ |
926 | void sqlite3TreeViewBareIdList( |
927 | TreeView *pView, |
928 | const IdList *pList, |
929 | const char *zLabel |
930 | ){ |
931 | if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST" ; |
932 | if( pList==0 ){ |
933 | sqlite3TreeViewLine(pView, "%s (empty)" , zLabel); |
934 | }else{ |
935 | int i; |
936 | sqlite3TreeViewLine(pView, "%s" , zLabel); |
937 | for(i=0; i<pList->nId; i++){ |
938 | char *zName = pList->a[i].zName; |
939 | int moreToFollow = i<pList->nId - 1; |
940 | if( zName==0 ) zName = "(null)" ; |
941 | sqlite3TreeViewPush(&pView, moreToFollow); |
942 | sqlite3TreeViewLine(pView, 0); |
943 | if( pList->eU4==EU4_NONE ){ |
944 | fprintf(stdout, "%s\n" , zName); |
945 | }else if( pList->eU4==EU4_IDX ){ |
946 | fprintf(stdout, "%s (%d)\n" , zName, pList->a[i].u4.idx); |
947 | }else{ |
948 | assert( pList->eU4==EU4_EXPR ); |
949 | if( pList->a[i].u4.pExpr==0 ){ |
950 | fprintf(stdout, "%s (pExpr=NULL)\n" , zName); |
951 | }else{ |
952 | fprintf(stdout, "%s\n" , zName); |
953 | sqlite3TreeViewPush(&pView, i<pList->nId-1); |
954 | sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0); |
955 | sqlite3TreeViewPop(&pView); |
956 | } |
957 | } |
958 | sqlite3TreeViewPop(&pView); |
959 | } |
960 | } |
961 | } |
962 | void sqlite3TreeViewIdList( |
963 | TreeView *pView, |
964 | const IdList *pList, |
965 | u8 moreToFollow, |
966 | const char *zLabel |
967 | ){ |
968 | sqlite3TreeViewPush(&pView, moreToFollow); |
969 | sqlite3TreeViewBareIdList(pView, pList, zLabel); |
970 | sqlite3TreeViewPop(&pView); |
971 | } |
972 | |
973 | /* |
974 | ** Generate a human-readable explanation of a list of Upsert objects |
975 | */ |
976 | void sqlite3TreeViewUpsert( |
977 | TreeView *pView, |
978 | const Upsert *pUpsert, |
979 | u8 moreToFollow |
980 | ){ |
981 | if( pUpsert==0 ) return; |
982 | sqlite3TreeViewPush(&pView, moreToFollow); |
983 | while( pUpsert ){ |
984 | int n; |
985 | sqlite3TreeViewPush(&pView, pUpsert->pNextUpsert!=0 || moreToFollow); |
986 | sqlite3TreeViewLine(pView, "ON CONFLICT DO %s" , |
987 | pUpsert->isDoUpdate ? "UPDATE" : "NOTHING" ); |
988 | n = (pUpsert->pUpsertSet!=0) + (pUpsert->pUpsertWhere!=0); |
989 | sqlite3TreeViewExprList(pView, pUpsert->pUpsertTarget, (n--)>0, "TARGET" ); |
990 | sqlite3TreeViewExprList(pView, pUpsert->pUpsertSet, (n--)>0, "SET" ); |
991 | if( pUpsert->pUpsertWhere ){ |
992 | sqlite3TreeViewItem(pView, "WHERE" , (n--)>0); |
993 | sqlite3TreeViewExpr(pView, pUpsert->pUpsertWhere, 0); |
994 | sqlite3TreeViewPop(&pView); |
995 | } |
996 | sqlite3TreeViewPop(&pView); |
997 | pUpsert = pUpsert->pNextUpsert; |
998 | } |
999 | sqlite3TreeViewPop(&pView); |
1000 | } |
1001 | |
1002 | #if TREETRACE_ENABLED |
1003 | /* |
1004 | ** Generate a human-readable diagram of the data structure that go |
1005 | ** into generating an DELETE statement. |
1006 | */ |
1007 | void sqlite3TreeViewDelete( |
1008 | const With *pWith, |
1009 | const SrcList *pTabList, |
1010 | const Expr *pWhere, |
1011 | const ExprList *pOrderBy, |
1012 | const Expr *pLimit, |
1013 | const Trigger *pTrigger |
1014 | ){ |
1015 | int n = 0; |
1016 | TreeView *pView = 0; |
1017 | sqlite3TreeViewPush(&pView, 0); |
1018 | sqlite3TreeViewLine(pView, "DELETE" ); |
1019 | if( pWith ) n++; |
1020 | if( pTabList ) n++; |
1021 | if( pWhere ) n++; |
1022 | if( pOrderBy ) n++; |
1023 | if( pLimit ) n++; |
1024 | if( pTrigger ) n++; |
1025 | if( pWith ){ |
1026 | sqlite3TreeViewPush(&pView, (--n)>0); |
1027 | sqlite3TreeViewWith(pView, pWith, 0); |
1028 | sqlite3TreeViewPop(&pView); |
1029 | } |
1030 | if( pTabList ){ |
1031 | sqlite3TreeViewPush(&pView, (--n)>0); |
1032 | sqlite3TreeViewLine(pView, "FROM" ); |
1033 | sqlite3TreeViewSrcList(pView, pTabList); |
1034 | sqlite3TreeViewPop(&pView); |
1035 | } |
1036 | if( pWhere ){ |
1037 | sqlite3TreeViewPush(&pView, (--n)>0); |
1038 | sqlite3TreeViewLine(pView, "WHERE" ); |
1039 | sqlite3TreeViewExpr(pView, pWhere, 0); |
1040 | sqlite3TreeViewPop(&pView); |
1041 | } |
1042 | if( pOrderBy ){ |
1043 | sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY" ); |
1044 | } |
1045 | if( pLimit ){ |
1046 | sqlite3TreeViewPush(&pView, (--n)>0); |
1047 | sqlite3TreeViewLine(pView, "LIMIT" ); |
1048 | sqlite3TreeViewExpr(pView, pLimit, 0); |
1049 | sqlite3TreeViewPop(&pView); |
1050 | } |
1051 | if( pTrigger ){ |
1052 | sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); |
1053 | } |
1054 | sqlite3TreeViewPop(&pView); |
1055 | } |
1056 | #endif /* TREETRACE_ENABLED */ |
1057 | |
1058 | #if TREETRACE_ENABLED |
1059 | /* |
1060 | ** Generate a human-readable diagram of the data structure that go |
1061 | ** into generating an INSERT statement. |
1062 | */ |
1063 | void sqlite3TreeViewInsert( |
1064 | const With *pWith, |
1065 | const SrcList *pTabList, |
1066 | const IdList *pColumnList, |
1067 | const Select *pSelect, |
1068 | const ExprList *pExprList, |
1069 | int onError, |
1070 | const Upsert *pUpsert, |
1071 | const Trigger *pTrigger |
1072 | ){ |
1073 | TreeView *pView = 0; |
1074 | int n = 0; |
1075 | const char *zLabel = "INSERT" ; |
1076 | switch( onError ){ |
1077 | case OE_Replace: zLabel = "REPLACE" ; break; |
1078 | case OE_Ignore: zLabel = "INSERT OR IGNORE" ; break; |
1079 | case OE_Rollback: zLabel = "INSERT OR ROLLBACK" ; break; |
1080 | case OE_Abort: zLabel = "INSERT OR ABORT" ; break; |
1081 | case OE_Fail: zLabel = "INSERT OR FAIL" ; break; |
1082 | } |
1083 | sqlite3TreeViewPush(&pView, 0); |
1084 | sqlite3TreeViewLine(pView, zLabel); |
1085 | if( pWith ) n++; |
1086 | if( pTabList ) n++; |
1087 | if( pColumnList ) n++; |
1088 | if( pSelect ) n++; |
1089 | if( pExprList ) n++; |
1090 | if( pUpsert ) n++; |
1091 | if( pTrigger ) n++; |
1092 | if( pWith ){ |
1093 | sqlite3TreeViewPush(&pView, (--n)>0); |
1094 | sqlite3TreeViewWith(pView, pWith, 0); |
1095 | sqlite3TreeViewPop(&pView); |
1096 | } |
1097 | if( pTabList ){ |
1098 | sqlite3TreeViewPush(&pView, (--n)>0); |
1099 | sqlite3TreeViewLine(pView, "INTO" ); |
1100 | sqlite3TreeViewSrcList(pView, pTabList); |
1101 | sqlite3TreeViewPop(&pView); |
1102 | } |
1103 | if( pColumnList ){ |
1104 | sqlite3TreeViewIdList(pView, pColumnList, (--n)>0, "COLUMNS" ); |
1105 | } |
1106 | if( pSelect ){ |
1107 | sqlite3TreeViewPush(&pView, (--n)>0); |
1108 | sqlite3TreeViewLine(pView, "DATA-SOURCE" ); |
1109 | sqlite3TreeViewSelect(pView, pSelect, 0); |
1110 | sqlite3TreeViewPop(&pView); |
1111 | } |
1112 | if( pExprList ){ |
1113 | sqlite3TreeViewExprList(pView, pExprList, (--n)>0, "VALUES" ); |
1114 | } |
1115 | if( pUpsert ){ |
1116 | sqlite3TreeViewPush(&pView, (--n)>0); |
1117 | sqlite3TreeViewLine(pView, "UPSERT" ); |
1118 | sqlite3TreeViewUpsert(pView, pUpsert, 0); |
1119 | sqlite3TreeViewPop(&pView); |
1120 | } |
1121 | if( pTrigger ){ |
1122 | sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); |
1123 | } |
1124 | sqlite3TreeViewPop(&pView); |
1125 | } |
1126 | #endif /* TREETRACE_ENABLED */ |
1127 | |
1128 | #if TREETRACE_ENABLED |
1129 | /* |
1130 | ** Generate a human-readable diagram of the data structure that go |
1131 | ** into generating an UPDATE statement. |
1132 | */ |
1133 | void sqlite3TreeViewUpdate( |
1134 | const With *pWith, |
1135 | const SrcList *pTabList, |
1136 | const ExprList *pChanges, |
1137 | const Expr *pWhere, |
1138 | int onError, |
1139 | const ExprList *pOrderBy, |
1140 | const Expr *pLimit, |
1141 | const Upsert *pUpsert, |
1142 | const Trigger *pTrigger |
1143 | ){ |
1144 | int n = 0; |
1145 | TreeView *pView = 0; |
1146 | const char *zLabel = "UPDATE" ; |
1147 | switch( onError ){ |
1148 | case OE_Replace: zLabel = "UPDATE OR REPLACE" ; break; |
1149 | case OE_Ignore: zLabel = "UPDATE OR IGNORE" ; break; |
1150 | case OE_Rollback: zLabel = "UPDATE OR ROLLBACK" ; break; |
1151 | case OE_Abort: zLabel = "UPDATE OR ABORT" ; break; |
1152 | case OE_Fail: zLabel = "UPDATE OR FAIL" ; break; |
1153 | } |
1154 | sqlite3TreeViewPush(&pView, 0); |
1155 | sqlite3TreeViewLine(pView, zLabel); |
1156 | if( pWith ) n++; |
1157 | if( pTabList ) n++; |
1158 | if( pChanges ) n++; |
1159 | if( pWhere ) n++; |
1160 | if( pOrderBy ) n++; |
1161 | if( pLimit ) n++; |
1162 | if( pUpsert ) n++; |
1163 | if( pTrigger ) n++; |
1164 | if( pWith ){ |
1165 | sqlite3TreeViewPush(&pView, (--n)>0); |
1166 | sqlite3TreeViewWith(pView, pWith, 0); |
1167 | sqlite3TreeViewPop(&pView); |
1168 | } |
1169 | if( pTabList ){ |
1170 | sqlite3TreeViewPush(&pView, (--n)>0); |
1171 | sqlite3TreeViewLine(pView, "FROM" ); |
1172 | sqlite3TreeViewSrcList(pView, pTabList); |
1173 | sqlite3TreeViewPop(&pView); |
1174 | } |
1175 | if( pChanges ){ |
1176 | sqlite3TreeViewExprList(pView, pChanges, (--n)>0, "SET" ); |
1177 | } |
1178 | if( pWhere ){ |
1179 | sqlite3TreeViewPush(&pView, (--n)>0); |
1180 | sqlite3TreeViewLine(pView, "WHERE" ); |
1181 | sqlite3TreeViewExpr(pView, pWhere, 0); |
1182 | sqlite3TreeViewPop(&pView); |
1183 | } |
1184 | if( pOrderBy ){ |
1185 | sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY" ); |
1186 | } |
1187 | if( pLimit ){ |
1188 | sqlite3TreeViewPush(&pView, (--n)>0); |
1189 | sqlite3TreeViewLine(pView, "LIMIT" ); |
1190 | sqlite3TreeViewExpr(pView, pLimit, 0); |
1191 | sqlite3TreeViewPop(&pView); |
1192 | } |
1193 | if( pUpsert ){ |
1194 | sqlite3TreeViewPush(&pView, (--n)>0); |
1195 | sqlite3TreeViewLine(pView, "UPSERT" ); |
1196 | sqlite3TreeViewUpsert(pView, pUpsert, 0); |
1197 | sqlite3TreeViewPop(&pView); |
1198 | } |
1199 | if( pTrigger ){ |
1200 | sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); |
1201 | } |
1202 | sqlite3TreeViewPop(&pView); |
1203 | } |
1204 | #endif /* TREETRACE_ENABLED */ |
1205 | |
1206 | #ifndef SQLITE_OMIT_TRIGGER |
1207 | /* |
1208 | ** Show a human-readable graph of a TriggerStep |
1209 | */ |
1210 | void sqlite3TreeViewTriggerStep( |
1211 | TreeView *pView, |
1212 | const TriggerStep *pStep, |
1213 | u8 moreToFollow, |
1214 | u8 showFullList |
1215 | ){ |
1216 | int cnt = 0; |
1217 | if( pStep==0 ) return; |
1218 | sqlite3TreeViewPush(&pView, |
1219 | moreToFollow || (showFullList && pStep->pNext!=0)); |
1220 | do{ |
1221 | if( cnt++ && pStep->pNext==0 ){ |
1222 | sqlite3TreeViewPop(&pView); |
1223 | sqlite3TreeViewPush(&pView, 0); |
1224 | } |
1225 | sqlite3TreeViewLine(pView, "%s" , pStep->zSpan ? pStep->zSpan : "RETURNING" ); |
1226 | }while( showFullList && (pStep = pStep->pNext)!=0 ); |
1227 | sqlite3TreeViewPop(&pView); |
1228 | } |
1229 | |
1230 | /* |
1231 | ** Show a human-readable graph of a Trigger |
1232 | */ |
1233 | void sqlite3TreeViewTrigger( |
1234 | TreeView *pView, |
1235 | const Trigger *pTrigger, |
1236 | u8 moreToFollow, |
1237 | u8 showFullList |
1238 | ){ |
1239 | int cnt = 0; |
1240 | if( pTrigger==0 ) return; |
1241 | sqlite3TreeViewPush(&pView, |
1242 | moreToFollow || (showFullList && pTrigger->pNext!=0)); |
1243 | do{ |
1244 | if( cnt++ && pTrigger->pNext==0 ){ |
1245 | sqlite3TreeViewPop(&pView); |
1246 | sqlite3TreeViewPush(&pView, 0); |
1247 | } |
1248 | sqlite3TreeViewLine(pView, "TRIGGER %s" , pTrigger->zName); |
1249 | sqlite3TreeViewPush(&pView, 0); |
1250 | sqlite3TreeViewTriggerStep(pView, pTrigger->step_list, 0, 1); |
1251 | sqlite3TreeViewPop(&pView); |
1252 | }while( showFullList && (pTrigger = pTrigger->pNext)!=0 ); |
1253 | sqlite3TreeViewPop(&pView); |
1254 | } |
1255 | #endif /* SQLITE_OMIT_TRIGGER */ |
1256 | |
1257 | |
1258 | /* |
1259 | ** These simplified versions of the tree-view routines omit unnecessary |
1260 | ** parameters. These variants are intended to be used from a symbolic |
1261 | ** debugger, such as "gdb", during interactive debugging sessions. |
1262 | ** |
1263 | ** This routines are given external linkage so that they will always be |
1264 | ** accessible to the debugging, and to avoid warnings about unused |
1265 | ** functions. But these routines only exist in debugging builds, so they |
1266 | ** do not contaminate the interface. |
1267 | */ |
1268 | void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); } |
1269 | void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);} |
1270 | void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); } |
1271 | void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); } |
1272 | void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); } |
1273 | void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); } |
1274 | void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); } |
1275 | #ifndef SQLITE_OMIT_TRIGGER |
1276 | void sqlite3ShowTriggerStep(const TriggerStep *p){ |
1277 | sqlite3TreeViewTriggerStep(0,p,0,0); |
1278 | } |
1279 | void sqlite3ShowTriggerStepList(const TriggerStep *p){ |
1280 | sqlite3TreeViewTriggerStep(0,p,0,1); |
1281 | } |
1282 | void sqlite3ShowTrigger(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,0); } |
1283 | void sqlite3ShowTriggerList(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,1);} |
1284 | #endif |
1285 | #ifndef SQLITE_OMIT_WINDOWFUNC |
1286 | void sqlite3ShowWindow(const Window *p){ sqlite3TreeViewWindow(0,p,0); } |
1287 | void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(0,p,0); } |
1288 | #endif |
1289 | |
1290 | #endif /* SQLITE_DEBUG */ |
1291 | |