/ Check-in [aee1c12f42]
Login

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

Overview
Comment:Further simplification and modularization of the EXPLAIN logic.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bytecode-function
Files: files | file ages | folders
SHA3-256: aee1c12f4227cea9e8c6295cee3ec11797422c31b48c9468f176eb52f8261fe8
User & Date: drh 2020-03-23 19:14:11
Context
2020-03-23
20:58
The bytecode() function now runs and sometimes works, but it untested and there are known problems. check-in: 6819b86eb2 user: drh tags: bytecode-function
19:14
Further simplification and modularization of the EXPLAIN logic. check-in: aee1c12f42 user: drh tags: bytecode-function
17:24
Begin breaking appear the sqlite3VdbeList() routine into subroutines that can be reused by the bytecode() table. check-in: 2c4dd79fbd user: drh tags: bytecode-function
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbeaux.c.

1460
1461
1462
1463
1464
1465
1466
1467

1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480

1481
1482
1483
1484
1485
1486
1487
....
1540
1541
1542
1543
1544
1545
1546



1547
1548
1549
1550
1551
1552
1553
1554
1555
....
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634

1635
1636
1637
1638
1639
1640
1641
1642
....
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744



1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
....
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855


1856
1857
1858
1859
1860
1861
1862
....
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141

2142


2143
2144
2145
2146
2147
2148
2149


2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181



2182
2183
2184
2185
2186
2187
2188
2189
2190

2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205

2206
2207
2208
2209
2210
2211
2212
** Some translation occurs:
**
**       "PX"      ->  "r[X]"
**       "PX@PY"   ->  "r[X..X+Y-1]"  or "r[x]" if y is 0 or 1
**       "PX@PY+1" ->  "r[X..X+Y]"    or "r[x]" if y is 0
**       "PY..PY"  ->  "r[X..Y]"      or "r[x]" if y<=x
*/
static int displayComment(

  const Op *pOp,     /* The opcode to be commented */
  const char *zP4,   /* Previously obtained value for P4 */
  char *zTemp,       /* Write result here */
  int nTemp          /* Space available in zTemp[] */
){
  const char *zOpName;
  const char *zSynopsis;
  int nOpName;
  int ii;
  char zAlt[50];
  StrAccum x;
  sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);


  zOpName = sqlite3OpcodeName(pOp->opcode);
  nOpName = sqlite3Strlen30(zOpName);
  if( zOpName[nOpName+1] ){
    int seenCom = 0;
    char c;
    zSynopsis = zOpName += nOpName + 1;
    if( strncmp(zSynopsis,"IF ",3)==0 ){
................................................................................
    }
    if( !seenCom && pOp->zComment ){
      sqlite3_str_appendf(&x, "; %s", pOp->zComment);
    }
  }else if( pOp->zComment ){
    sqlite3_str_appendall(&x, pOp->zComment);
  }



  sqlite3StrAccumFinish(&x);
  return x.nChar;
}
#endif /* SQLITE_DEBUG */

#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
** Translate the P4.pExpr value for an OP_CursorHint opcode into text
** that can be displayed in the P4 column of EXPLAIN output.
................................................................................


#if VDBE_DISPLAY_P4
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
static char *displayP4(Op *pOp, char *zTemp, int nTemp){
  char *zP4 = zTemp;
  StrAccum x;
  assert( nTemp>=20 );

  sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
  switch( pOp->p4type ){
    case P4_KEYINFO: {
      int j;
      KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
      assert( pKeyInfo->aSortFlags!=0 );
      sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField);
      for(j=0; j<pKeyInfo->nKeyField; j++){
................................................................................
      int i;
      int *ai = pOp->p4.ai;
      int n = ai[0];   /* The first element of an INTARRAY is always the
                       ** count of the number of elements to follow */
      for(i=1; i<=n; i++){
        sqlite3_str_appendf(&x, ",%d", ai[i]);
      }
      zTemp[0] = '[';
      sqlite3_str_append(&x, "]", 1);
      break;
    }
    case P4_SUBPROGRAM: {
      sqlite3_str_appendf(&x, "program");
      break;
    }
    case P4_DYNBLOB:
    case P4_ADVANCE: {
      zTemp[0] = 0;
      break;
    }
    case P4_TABLE: {
      sqlite3_str_appendf(&x, "%s", pOp->p4.pTab->zName);
      break;
    }
    default: {
      zP4 = pOp->p4.z;
      if( zP4==0 ){
        zP4 = zTemp;
        zTemp[0] = 0;
      }
    }



  }
  sqlite3StrAccumFinish(&x);
  assert( zP4!=0 );
  return zP4;
}
#endif /* VDBE_DISPLAY_P4 */

/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
**
** The prepared statements need to know in advance the complete set of
................................................................................

#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Print a single opcode.  This routine is used for debugging only.
*/
void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
  char *zP4;
  char zPtr[50];
  char zCom[100];
  static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
  if( pOut==0 ) pOut = stdout;
  zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  displayComment(pOp, zP4, zCom, sizeof(zCom));
#else
  zCom[0] = 0;
#endif
  /* NB:  The sqlite3OpcodeName() function is implemented by code created
  ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
  ** information from the vdbe.c source text */
  fprintf(pOut, zFormat1, pc, 
      sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
      zCom
  );
  fflush(pOut);


}
#endif

/*
** Initialize an array of N Mem element.
*/
static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
................................................................................
  if( rc==SQLITE_OK ){
    pOp = aOp + i;
    if( db->u1.isInterrupted ){
      p->rc = SQLITE_INTERRUPT;
      rc = SQLITE_ERROR;
      sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    }else{
      char *zP4;
      if( p->explain==1 ){
        pMem->flags = MEM_Int;
        pMem->u.i = i;                                /* Program counter */
        pMem++;
    

        pMem->flags = MEM_Static|MEM_Str|MEM_Term;


        pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
        assert( pMem->z!=0 );
        pMem->n = sqlite3Strlen30(pMem->z);
        pMem->enc = SQLITE_UTF8;
        pMem++;
      }



      pMem->flags = MEM_Int;
      pMem->u.i = pOp->p1;                          /* P1 */
      pMem++;

      pMem->flags = MEM_Int;
      pMem->u.i = pOp->p2;                          /* P2 */
      pMem++;

      pMem->flags = MEM_Int;
      pMem->u.i = pOp->p3;                          /* P3 */
      pMem++;

      if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
        assert( p->db->mallocFailed );
        return SQLITE_ERROR;
      }
      pMem->flags = MEM_Str|MEM_Term;
      zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
      if( zP4!=pMem->z ){
        pMem->n = 0;
        sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
      }else{
        assert( pMem->z!=0 );
        pMem->n = sqlite3Strlen30(pMem->z);
        pMem->enc = SQLITE_UTF8;
      }
      pMem++;

      if( p->explain==1 ){
        if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
          assert( p->db->mallocFailed );
          return SQLITE_ERROR;



        }
        pMem->flags = MEM_Str|MEM_Term;
        pMem->n = 2;
        sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5);   /* P5 */
        pMem->enc = SQLITE_UTF8;
        pMem++;
    
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
        if( sqlite3VdbeMemClearAndResize(pMem, 500) ){

          assert( p->db->mallocFailed );
          return SQLITE_ERROR;
        }
        pMem->flags = MEM_Str|MEM_Term;
        pMem->n = displayComment(pOp, zP4, pMem->z, 500);
        pMem->enc = SQLITE_UTF8;
#else
        pMem->flags = MEM_Null;                       /* Comment */
#endif
      }

      p->nResColumn = 8 - 4*(p->explain-1);
      p->pResultSet = &p->aMem[1];
      p->rc = SQLITE_OK;
      rc = SQLITE_ROW;

    }
  }
  return rc;
}
#endif /* SQLITE_OMIT_EXPLAIN */

#ifdef SQLITE_DEBUG







|
>

|
<
<







<

>







 







>
>
>
|
<







 







|
|

<
>
|







 







|




|




<



|




<
<
<
|
|
>
>
>

|
<
<







 







|
<


|

|

|






|


>
>







 







|
|
|
|
|
<
>
|
>
>
|
<
<
|
|
<
<
>
>
|
|
|
|
|
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
|
<
<
>
>
>
|
<
<
<
<
<
<
<
<
>
|
|
<
<
<
|
|
<
<
<
<
<
<
|
|
>







1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470


1471
1472
1473
1474
1475
1476
1477

1478
1479
1480
1481
1482
1483
1484
1485
1486
....
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549

1550
1551
1552
1553
1554
1555
1556
....
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634

1635
1636
1637
1638
1639
1640
1641
1642
1643
....
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731

1732
1733
1734
1735
1736
1737
1738
1739



1740
1741
1742
1743
1744
1745
1746


1747
1748
1749
1750
1751
1752
1753
....
1829
1830
1831
1832
1833
1834
1835
1836

1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
....
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139

2140
2141
2142
2143
2144


2145
2146


2147
2148
2149
2150
2151
2152
2153
2154

2155













2156







2157


2158
2159
2160
2161








2162
2163
2164



2165
2166






2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
** Some translation occurs:
**
**       "PX"      ->  "r[X]"
**       "PX@PY"   ->  "r[X..X+Y-1]"  or "r[x]" if y is 0 or 1
**       "PX@PY+1" ->  "r[X..X+Y]"    or "r[x]" if y is 0
**       "PY..PY"  ->  "r[X..Y]"      or "r[x]" if y<=x
*/
static char *displayComment(
  sqlite3 *db,       /* Optional - Oom error reporting only */
  const Op *pOp,     /* The opcode to be commented */
  const char *zP4    /* Previously obtained value for P4 */


){
  const char *zOpName;
  const char *zSynopsis;
  int nOpName;
  int ii;
  char zAlt[50];
  StrAccum x;


  sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
  zOpName = sqlite3OpcodeName(pOp->opcode);
  nOpName = sqlite3Strlen30(zOpName);
  if( zOpName[nOpName+1] ){
    int seenCom = 0;
    char c;
    zSynopsis = zOpName += nOpName + 1;
    if( strncmp(zSynopsis,"IF ",3)==0 ){
................................................................................
    }
    if( !seenCom && pOp->zComment ){
      sqlite3_str_appendf(&x, "; %s", pOp->zComment);
    }
  }else if( pOp->zComment ){
    sqlite3_str_appendall(&x, pOp->zComment);
  }
  if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){
    sqlite3OomFault(db);
  }
  return sqlite3StrAccumFinish(&x);

}
#endif /* SQLITE_DEBUG */

#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
** Translate the P4.pExpr value for an OP_CursorHint opcode into text
** that can be displayed in the P4 column of EXPLAIN output.
................................................................................


#if VDBE_DISPLAY_P4
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
static char *displayP4(sqlite3 *db, Op *pOp){
  char *zP4 = 0;
  StrAccum x;


  sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
  switch( pOp->p4type ){
    case P4_KEYINFO: {
      int j;
      KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
      assert( pKeyInfo->aSortFlags!=0 );
      sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField);
      for(j=0; j<pKeyInfo->nKeyField; j++){
................................................................................
      int i;
      int *ai = pOp->p4.ai;
      int n = ai[0];   /* The first element of an INTARRAY is always the
                       ** count of the number of elements to follow */
      for(i=1; i<=n; i++){
        sqlite3_str_appendf(&x, ",%d", ai[i]);
      }
      if( !x.accError ) x.zText[0] = '[';
      sqlite3_str_append(&x, "]", 1);
      break;
    }
    case P4_SUBPROGRAM: {
      zP4 = "program";
      break;
    }
    case P4_DYNBLOB:
    case P4_ADVANCE: {

      break;
    }
    case P4_TABLE: {
      zP4 = pOp->p4.pTab->zName;
      break;
    }
    default: {
      zP4 = pOp->p4.z;



    }
  }
  if( zP4 ) sqlite3_str_appendall(&x, zP4);
  if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){
    sqlite3OomFault(db);
  }
  return sqlite3StrAccumFinish(&x);


}
#endif /* VDBE_DISPLAY_P4 */

/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
**
** The prepared statements need to know in advance the complete set of
................................................................................

#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Print a single opcode.  This routine is used for debugging only.
*/
void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
  char *zP4;
  char *zCom;

  static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
  if( pOut==0 ) pOut = stdout;
  zP4 = displayP4(0, pOp);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  zCom = displayComment(0, pOp, zP4);
#else
  zCom = 0;
#endif
  /* NB:  The sqlite3OpcodeName() function is implemented by code created
  ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
  ** information from the vdbe.c source text */
  fprintf(pOut, zFormat1, pc, 
      sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
      zCom ? zCom : ""
  );
  fflush(pOut);
  sqlite3_free(zP4);
  sqlite3_free(zCom);
}
#endif

/*
** Initialize an array of N Mem element.
*/
static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
................................................................................
  if( rc==SQLITE_OK ){
    pOp = aOp + i;
    if( db->u1.isInterrupted ){
      p->rc = SQLITE_INTERRUPT;
      rc = SQLITE_ERROR;
      sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
    }else{
      char *zP4 = displayP4(db, pOp);
      if( p->explain==2 ){
        sqlite3VdbeMemSetInt64(pMem, pOp->p1);
        sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
        sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);

        sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);     
        p->nResColumn = 4;
      }else{
        sqlite3VdbeMemSetInt64(pMem+0, i);
        sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),


                             -1, SQLITE_UTF8, SQLITE_STATIC);
        sqlite3VdbeMemSetInt64(pMem+2, pOp->p1);


        sqlite3VdbeMemSetInt64(pMem+3, pOp->p2);
        sqlite3VdbeMemSetInt64(pMem+4, pOp->p3);
        /* pMem+5 for p4 is done last */
        sqlite3VdbeMemSetInt64(pMem+6, pOp->p5);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
        {
          char *zCom = displayComment(db, pOp, zP4);
          sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free);

        }













#else







        sqlite3VdbeMemSetNull(pMem+7);


#endif
        sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
        p->nResColumn = 8;
      }








      p->pResultSet = pMem;
      if( db->mallocFailed ){
        p->rc = SQLITE_NOMEM;



        rc = SQLITE_ERROR;
      }else{






        p->rc = SQLITE_OK;
        rc = SQLITE_ROW;
      }
    }
  }
  return rc;
}
#endif /* SQLITE_OMIT_EXPLAIN */

#ifdef SQLITE_DEBUG

Changes to test/distinct.test.

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
}

proc do_temptables_test {tn sql temptables} {
  uplevel [list do_test $tn [subst -novar {
    set ret ""
    db eval "EXPLAIN [set sql]" {
      if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} { 
        if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
        if {$p5 == "08"} {
          lappend ret hash
        } else {
          lappend ret btree
        }
      }
    }
    set ret







|
|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
}

proc do_temptables_test {tn sql temptables} {
  uplevel [list do_test $tn [subst -novar {
    set ret ""
    db eval "EXPLAIN [set sql]" {
      if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} { 
        if {$p5!=8 && $p5!=0} { error "p5 = $p5" }
        if {$p5==8} {
          lappend ret hash
        } else {
          lappend ret btree
        }
      }
    }
    set ret