/ Check-in [956fef36]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Optimizations to the new EQP framework.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rework-EQP
Files: files | file ages | folders
SHA3-256: 956fef361a795bd081d8e23ce4075dc8aafcee63ab7275d13b657b529d185b30
User & Date: drh 2018-05-03 19:47:14
Context
2018-05-03
19:56
Overhaul of EXPLAIN QUERY PLAN. The output is now in the form of a tree. More details of the query plan are shown, and what is shown is truer to what actually happens. check-in: ff01bbda user: drh tags: trunk
19:47
Optimizations to the new EQP framework. Closed-Leaf check-in: 956fef36 user: drh tags: rework-EQP
01:37
Enhance EXPLAIN QUERY PLAN to report the generation of constant rows using VALUES or just a SELECT without FROM. check-in: c75eee69 user: drh tags: rework-EQP
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/expr.c.

2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
....
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
        */
        Select *pSelect = pExpr->x.pSelect;
        ExprList *pEList = pSelect->pEList;

        ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY",
            jmpIfDynamic>=0?"":"CORRELATED "
        ));
        ExplainQueryPlanSetId(pParse, pSelect);
        assert( !isRowid );
        /* If the LHS and RHS of the IN operator do not match, that
        ** error will have been caught long before we reach this point. */
        if( ALWAYS(pEList->nExpr==nVal) ){
          SelectDest dest;
          int i;
          sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
................................................................................
      testcase( pExpr->op==TK_SELECT );
      assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
      assert( ExprHasProperty(pExpr, EP_xIsSelect) );

      pSel = pExpr->x.pSelect;
      ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY",
            jmpIfDynamic>=0?"":"CORRELATED "));
      ExplainQueryPlanSetId(pParse, pSel);
      nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
      sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
      pParse->nMem += nReg;
      if( pExpr->op==TK_SELECT ){
        dest.eDest = SRT_Mem;
        dest.iSdst = dest.iSDParm;
        dest.nSdst = nReg;







<







 







<







2642
2643
2644
2645
2646
2647
2648

2649
2650
2651
2652
2653
2654
2655
....
2765
2766
2767
2768
2769
2770
2771

2772
2773
2774
2775
2776
2777
2778
        */
        Select *pSelect = pExpr->x.pSelect;
        ExprList *pEList = pSelect->pEList;

        ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY",
            jmpIfDynamic>=0?"":"CORRELATED "
        ));

        assert( !isRowid );
        /* If the LHS and RHS of the IN operator do not match, that
        ** error will have been caught long before we reach this point. */
        if( ALWAYS(pEList->nExpr==nVal) ){
          SelectDest dest;
          int i;
          sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
................................................................................
      testcase( pExpr->op==TK_SELECT );
      assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
      assert( ExprHasProperty(pExpr, EP_xIsSelect) );

      pSel = pExpr->x.pSelect;
      ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY",
            jmpIfDynamic>=0?"":"CORRELATED "));

      nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
      sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
      pParse->nMem += nReg;
      if( pExpr->op==TK_SELECT ){
        dest.eDest = SRT_Mem;
        dest.iSdst = dest.iSDParm;
        dest.nSdst = nReg;

Changes to src/select.c.

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
....
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
....
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
....
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
....
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
....
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
....
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
....
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
....
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
....
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
....
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
  pNew->op = TK_SELECT;
  pNew->selFlags = selFlags;
  pNew->iLimit = 0;
  pNew->iOffset = 0;
#if SELECTTRACE_ENABLED
  pNew->zSelName[0] = 0;
#endif
#if SELECTTRACE_ENABLED || !defined(SQLITE_OMIT_EXPLAIN)
  pNew->iSelectId = 0;
#endif
  pNew->addrOpenEphm[0] = -1;
  pNew->addrOpenEphm[1] = -1;
  pNew->nSelectRow = 0;
  if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
  pNew->pSrc = pSrc;
  pNew->pWhere = pWhere;
  pNew->pGroupBy = pGroupBy;
................................................................................

  /* Detach the ORDER BY clause from the compound SELECT */
  p->pOrderBy = 0;

  /* Store the results of the setup-query in Queue. */
  pSetup->pNext = 0;
  ExplainQueryPlan((pParse, 1, "SETUP"));
  ExplainQueryPlanSetId(pParse, pSetup);
  rc = sqlite3Select(pParse, pSetup, &destQueue);
  pSetup->pNext = p;
  if( rc ) goto end_of_recursive_query;

  /* Find the next row in the Queue and output that row */
  addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v);

................................................................................
  ** the value for the recursive-table. Store the results in the Queue.
  */
  if( p->selFlags & SF_Aggregate ){
    sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
  }else{
    p->pPrior = 0;
    ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));
    ExplainQueryPlanSetId(pParse, p);
    sqlite3Select(pParse, p, &destQueue);
    assert( p->pPrior==0 );
    p->pPrior = pSetup;
  }

  /* Keep running the loop until the Queue is empty */
  sqlite3VdbeGoto(v, addrTop);
................................................................................
  /* Compound SELECTs that have an ORDER BY clause are handled separately.
  */
  if( p->pOrderBy ){
    return multiSelectOrderBy(pParse, p, pDest);
  }else{

#ifndef SQLITE_OMIT_EXPLAIN
    if( p->pNext==0 ){
      ExplainQueryPlan((pParse, 1, "COMPOUND QUERY"));
    }
    if( pPrior->pPrior==0 ){
      ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY"));
      ExplainQueryPlanSetId(pParse, pPrior);
    }
#endif

    /* Generate code for the left and right SELECT statements.
    */
    switch( p->op ){
      case TK_ALL: {
................................................................................
          VdbeComment((v, "Jump ahead if LIMIT reached"));
          if( p->iOffset ){
            sqlite3VdbeAddOp3(v, OP_OffsetLimit,
                              p->iLimit, p->iOffset+1, p->iOffset);
          }
        }
        ExplainQueryPlan((pParse, 1, "UNION ALL"));
        ExplainQueryPlanSetId(pParse, p);
        rc = sqlite3Select(pParse, p, &dest);
        testcase( rc!=SQLITE_OK );
        pDelete = p->pPrior;
        p->pPrior = pPrior;
        p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
        if( pPrior->pLimit
         && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
................................................................................
        }
        p->pPrior = 0;
        pLimit = p->pLimit;
        p->pLimit = 0;
        uniondest.eDest = op;
        ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
                          selectOpName(p->op)));
        ExplainQueryPlanSetId(pParse, p);
        rc = sqlite3Select(pParse, p, &uniondest);
        testcase( rc!=SQLITE_OK );
        /* Query flattening in sqlite3Select() might refill p->pOrderBy.
        ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
        sqlite3ExprListDelete(db, p->pOrderBy);
        pDelete = p->pPrior;
        p->pPrior = pPrior;
................................................................................
        p->addrOpenEphm[1] = addr;
        p->pPrior = 0;
        pLimit = p->pLimit;
        p->pLimit = 0;
        intersectdest.iSDParm = tab2;
        ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
                          selectOpName(p->op)));
        ExplainQueryPlanSetId(pParse, p);
        rc = sqlite3Select(pParse, p, &intersectdest);
        testcase( rc!=SQLITE_OK );
        pDelete = p->pPrior;
        p->pPrior = pPrior;
        if( p->nSelectRow>pPrior->nSelectRow ){
          p->nSelectRow = pPrior->nSelectRow;
        }
................................................................................
  ** left of the compound operator - the "A" select.
  */
  addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
  VdbeComment((v, "left SELECT"));
  pPrior->iLimit = regLimitA;
  ExplainQueryPlan((pParse, 1, "LEFT"));
  ExplainQueryPlanSetId(pParse, pPrior);
  sqlite3Select(pParse, pPrior, &destA);
  sqlite3VdbeEndCoroutine(v, regAddrA);
  sqlite3VdbeJumpHere(v, addr1);

  /* Generate a coroutine to evaluate the SELECT statement on 
  ** the right - the "B" select
  */
................................................................................
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
  VdbeComment((v, "right SELECT"));
  savedLimit = p->iLimit;
  savedOffset = p->iOffset;
  p->iLimit = regLimitB;
  p->iOffset = 0;  
  ExplainQueryPlan((pParse, 1, "RIGHT"));
  ExplainQueryPlanSetId(pParse, p);
  sqlite3Select(pParse, p, &destB);
  p->iLimit = savedLimit;
  p->iOffset = savedOffset;
  sqlite3VdbeEndCoroutine(v, regAddrB);

  /* Generate a subroutine that outputs the current row of the A
  ** select as the next output row of the compound select.
................................................................................
     
      pItem->regReturn = ++pParse->nMem;
      sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
      VdbeComment((v, "%s", pItem->pTab->zName));
      pItem->addrFillSub = addrTop;
      sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
      ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub));
      ExplainQueryPlanSetId(pParse, pSub);
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowLogEst = pSub->nSelectRow;
      pItem->fg.viaCoroutine = 1;
      pItem->regResult = dest.iSdst;
      sqlite3VdbeEndCoroutine(v, pItem->regReturn);
      sqlite3VdbeJumpHere(v, addrTop-1);
      sqlite3ClearTempRegCache(pParse);
................................................................................
      if( pPrior ){
        sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
        assert( pPrior->pSelect!=0 );
        pSub->nSelectRow = pPrior->pSelect->nSelectRow;
      }else{
        sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
        ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub));
        ExplainQueryPlanSetId(pParse,pSub);
        sqlite3Select(pParse, pSub, &dest);
      }
      pItem->pTab->nRowLogEst = pSub->nSelectRow;
      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
      retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
      VdbeComment((v, "end %s", pItem->pTab->zName));
      sqlite3VdbeChangeP1(v, topAddr, retAddr);







<
<
<







 







<







 







<







 







|

<
<

<







 







<







 







<







 







<







 







<







 







<







 







<







 







<







144
145
146
147
148
149
150



151
152
153
154
155
156
157
....
2284
2285
2286
2287
2288
2289
2290

2291
2292
2293
2294
2295
2296
2297
....
2319
2320
2321
2322
2323
2324
2325

2326
2327
2328
2329
2330
2331
2332
....
2483
2484
2485
2486
2487
2488
2489
2490
2491


2492

2493
2494
2495
2496
2497
2498
2499
....
2516
2517
2518
2519
2520
2521
2522

2523
2524
2525
2526
2527
2528
2529
....
2586
2587
2588
2589
2590
2591
2592

2593
2594
2595
2596
2597
2598
2599
....
2664
2665
2666
2667
2668
2669
2670

2671
2672
2673
2674
2675
2676
2677
....
3171
3172
3173
3174
3175
3176
3177

3178
3179
3180
3181
3182
3183
3184
....
3186
3187
3188
3189
3190
3191
3192

3193
3194
3195
3196
3197
3198
3199
....
5558
5559
5560
5561
5562
5563
5564

5565
5566
5567
5568
5569
5570
5571
....
5597
5598
5599
5600
5601
5602
5603

5604
5605
5606
5607
5608
5609
5610
  pNew->op = TK_SELECT;
  pNew->selFlags = selFlags;
  pNew->iLimit = 0;
  pNew->iOffset = 0;
#if SELECTTRACE_ENABLED
  pNew->zSelName[0] = 0;
#endif



  pNew->addrOpenEphm[0] = -1;
  pNew->addrOpenEphm[1] = -1;
  pNew->nSelectRow = 0;
  if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
  pNew->pSrc = pSrc;
  pNew->pWhere = pWhere;
  pNew->pGroupBy = pGroupBy;
................................................................................

  /* Detach the ORDER BY clause from the compound SELECT */
  p->pOrderBy = 0;

  /* Store the results of the setup-query in Queue. */
  pSetup->pNext = 0;
  ExplainQueryPlan((pParse, 1, "SETUP"));

  rc = sqlite3Select(pParse, pSetup, &destQueue);
  pSetup->pNext = p;
  if( rc ) goto end_of_recursive_query;

  /* Find the next row in the Queue and output that row */
  addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v);

................................................................................
  ** the value for the recursive-table. Store the results in the Queue.
  */
  if( p->selFlags & SF_Aggregate ){
    sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
  }else{
    p->pPrior = 0;
    ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));

    sqlite3Select(pParse, p, &destQueue);
    assert( p->pPrior==0 );
    p->pPrior = pSetup;
  }

  /* Keep running the loop until the Queue is empty */
  sqlite3VdbeGoto(v, addrTop);
................................................................................
  /* Compound SELECTs that have an ORDER BY clause are handled separately.
  */
  if( p->pOrderBy ){
    return multiSelectOrderBy(pParse, p, pDest);
  }else{

#ifndef SQLITE_OMIT_EXPLAIN
    if( pPrior->pPrior==0 ){
      ExplainQueryPlan((pParse, 1, "COMPOUND QUERY"));


      ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY"));

    }
#endif

    /* Generate code for the left and right SELECT statements.
    */
    switch( p->op ){
      case TK_ALL: {
................................................................................
          VdbeComment((v, "Jump ahead if LIMIT reached"));
          if( p->iOffset ){
            sqlite3VdbeAddOp3(v, OP_OffsetLimit,
                              p->iLimit, p->iOffset+1, p->iOffset);
          }
        }
        ExplainQueryPlan((pParse, 1, "UNION ALL"));

        rc = sqlite3Select(pParse, p, &dest);
        testcase( rc!=SQLITE_OK );
        pDelete = p->pPrior;
        p->pPrior = pPrior;
        p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
        if( pPrior->pLimit
         && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
................................................................................
        }
        p->pPrior = 0;
        pLimit = p->pLimit;
        p->pLimit = 0;
        uniondest.eDest = op;
        ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
                          selectOpName(p->op)));

        rc = sqlite3Select(pParse, p, &uniondest);
        testcase( rc!=SQLITE_OK );
        /* Query flattening in sqlite3Select() might refill p->pOrderBy.
        ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
        sqlite3ExprListDelete(db, p->pOrderBy);
        pDelete = p->pPrior;
        p->pPrior = pPrior;
................................................................................
        p->addrOpenEphm[1] = addr;
        p->pPrior = 0;
        pLimit = p->pLimit;
        p->pLimit = 0;
        intersectdest.iSDParm = tab2;
        ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
                          selectOpName(p->op)));

        rc = sqlite3Select(pParse, p, &intersectdest);
        testcase( rc!=SQLITE_OK );
        pDelete = p->pPrior;
        p->pPrior = pPrior;
        if( p->nSelectRow>pPrior->nSelectRow ){
          p->nSelectRow = pPrior->nSelectRow;
        }
................................................................................
  ** left of the compound operator - the "A" select.
  */
  addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
  VdbeComment((v, "left SELECT"));
  pPrior->iLimit = regLimitA;
  ExplainQueryPlan((pParse, 1, "LEFT"));

  sqlite3Select(pParse, pPrior, &destA);
  sqlite3VdbeEndCoroutine(v, regAddrA);
  sqlite3VdbeJumpHere(v, addr1);

  /* Generate a coroutine to evaluate the SELECT statement on 
  ** the right - the "B" select
  */
................................................................................
  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
  VdbeComment((v, "right SELECT"));
  savedLimit = p->iLimit;
  savedOffset = p->iOffset;
  p->iLimit = regLimitB;
  p->iOffset = 0;  
  ExplainQueryPlan((pParse, 1, "RIGHT"));

  sqlite3Select(pParse, p, &destB);
  p->iLimit = savedLimit;
  p->iOffset = savedOffset;
  sqlite3VdbeEndCoroutine(v, regAddrB);

  /* Generate a subroutine that outputs the current row of the A
  ** select as the next output row of the compound select.
................................................................................
     
      pItem->regReturn = ++pParse->nMem;
      sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
      VdbeComment((v, "%s", pItem->pTab->zName));
      pItem->addrFillSub = addrTop;
      sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
      ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub));

      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowLogEst = pSub->nSelectRow;
      pItem->fg.viaCoroutine = 1;
      pItem->regResult = dest.iSdst;
      sqlite3VdbeEndCoroutine(v, pItem->regReturn);
      sqlite3VdbeJumpHere(v, addrTop-1);
      sqlite3ClearTempRegCache(pParse);
................................................................................
      if( pPrior ){
        sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
        assert( pPrior->pSelect!=0 );
        pSub->nSelectRow = pPrior->pSelect->nSelectRow;
      }else{
        sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
        ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub));

        sqlite3Select(pParse, pSub, &dest);
      }
      pItem->pTab->nRowLogEst = pSub->nSelectRow;
      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
      retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
      VdbeComment((v, "end %s", pItem->pTab->zName));
      sqlite3VdbeChangeP1(v, topAddr, retAddr);

Changes to src/sqliteInt.h.

2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
  LogEst nSelectRow;     /* Estimated number of result rows */
  u32 selFlags;          /* Various SF_* values */
  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
#if SELECTTRACE_ENABLED
  char zSelName[12];     /* Symbolic name of this SELECT use for debugging */
#endif
#if defined(SQLITETRACE_ENABLED) || !defined(SQLITE_OMIT_EXPLAIN)
  u32 iSelectId;         /* EXPLAIN QUERY PLAN select ID */
#endif
  int addrOpenEphm[2];   /* OP_OpenEphem opcodes related to this select */
  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */
  Expr *pHaving;         /* The HAVING clause */
  ExprList *pOrderBy;    /* The ORDER BY clause */
  Select *pPrior;        /* Prior select in a compound select statement */







<
<
<







2777
2778
2779
2780
2781
2782
2783



2784
2785
2786
2787
2788
2789
2790
  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
  LogEst nSelectRow;     /* Estimated number of result rows */
  u32 selFlags;          /* Various SF_* values */
  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
#if SELECTTRACE_ENABLED
  char zSelName[12];     /* Symbolic name of this SELECT use for debugging */
#endif



  int addrOpenEphm[2];   /* OP_OpenEphem opcodes related to this select */
  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */
  Expr *pHaving;         /* The HAVING clause */
  ExprList *pOrderBy;    /* The ORDER BY clause */
  Select *pPrior;        /* Prior select in a compound select statement */

Changes to src/treeview.c.

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    sqlite3TreeViewWith(pView, p->pWith, 1);
    cnt = 1;
    sqlite3TreeViewPush(pView, 1);
  }
  do{
#if SELECTTRACE_ENABLED
    sqlite3TreeViewLine(pView,
      "SELECT%s%s (%s/%d/%p) selFlags=0x%x nSelectRow=%d",
      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
      p->zSelName, p->iSelectId, p, p->selFlags,
      (int)p->nSelectRow
    );
#else
    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
      (int)p->nSelectRow







|


|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    sqlite3TreeViewWith(pView, p->pWith, 1);
    cnt = 1;
    sqlite3TreeViewPush(pView, 1);
  }
  do{
#if SELECTTRACE_ENABLED
    sqlite3TreeViewLine(pView,
      "SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d",
      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
      p->zSelName, p, p->selFlags,
      (int)p->nSelectRow
    );
#else
    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
      (int)p->nSelectRow

Changes to src/vdbe.h.

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#ifndef SQLITE_OMIT_EXPLAIN
  void sqlite3VdbeExplain(Parse*,u8,const char*,...);
  void sqlite3VdbeExplainPop(Parse*);
  int sqlite3VdbeExplainParent(Parse*);
# define ExplainQueryPlan(P)        sqlite3VdbeExplain P
# define ExplainQueryPlanPop(P)     sqlite3VdbeExplainPop(P)
# define ExplainQueryPlanParent(P)  sqlite3VdbeExplainParent(P)
# define ExplainQueryPlanSetId(P,S) (S)->iSelectId=(P)->addrExplain
#else
# define ExplainQueryPlan(P)
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0
# define ExplainQueryPlanSetId(P,S)
#endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);







<




<







201
202
203
204
205
206
207

208
209
210
211

212
213
214
215
216
217
218
#ifndef SQLITE_OMIT_EXPLAIN
  void sqlite3VdbeExplain(Parse*,u8,const char*,...);
  void sqlite3VdbeExplainPop(Parse*);
  int sqlite3VdbeExplainParent(Parse*);
# define ExplainQueryPlan(P)        sqlite3VdbeExplain P
# define ExplainQueryPlanPop(P)     sqlite3VdbeExplainPop(P)
# define ExplainQueryPlanParent(P)  sqlite3VdbeExplainParent(P)

#else
# define ExplainQueryPlan(P)
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0

#endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);