SQLite

Check-in [ede06dacdf]
Login

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

Overview
Comment:Enhance the sqlite3VdbeGetOp() routine so that it always returns a pointer to VdbeOp, even following an OOM fault. This simplifies error handling in callers. Cleanup to the column cache logic and the expr.c source module. (CVS 6691)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ede06dacdf7acab23cd9666a0a0d092a637bcb78
User & Date: drh 2009-05-29 19:00:13.000
Context
2009-05-30
10:46
In vacuum.c use "PagerIsMemdb(X)" instead of "PagerFile(X)->pMethods==0". (CVS 6692) (check-in: 874295ce71 user: danielk1977 tags: trunk)
2009-05-29
19:00
Enhance the sqlite3VdbeGetOp() routine so that it always returns a pointer to VdbeOp, even following an OOM fault. This simplifies error handling in callers. Cleanup to the column cache logic and the expr.c source module. (CVS 6691) (check-in: ede06dacdf user: drh tags: trunk)
14:39
Refinements in expression handling logic that have resulted from recent structural testing. (CVS 6690) (check-in: bd89f2c29b user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.440 2009/05/29 14:39:08 drh Exp $
*/
#include "sqliteInt.h"

/*
** Return the 'affinity' of the expression pExpr if any.
**
** If pExpr is a column, a reference to a column via an 'AS' alias,







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.441 2009/05/29 19:00:13 drh Exp $
*/
#include "sqliteInt.h"

/*
** Return the 'affinity' of the expression pExpr if any.
**
** If pExpr is a column, a reference to a column via an 'AS' alias,
1769
1770
1771
1772
1773
1774
1775



1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
*/
void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
  int i;
  int minLru;
  int idxLru;
  struct yColCache *p;




  /* First replace any existing entry */
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
      cacheEntryClear(pParse, p);
      p->iLevel = pParse->iCacheLevel;
      p->iReg = iReg;
      p->affChange = 0;
      p->lru = pParse->iCacheCnt++;
      return;
    }
  }
  if( iReg<=0 ) return;

  /* Find an empty slot and replace it */
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->iReg==0 ){
      p->iLevel = pParse->iCacheLevel;
      p->iTable = iTab;
      p->iColumn = iCol;







>
>
>











<







1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789

1790
1791
1792
1793
1794
1795
1796
*/
void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
  int i;
  int minLru;
  int idxLru;
  struct yColCache *p;

  assert( iReg>0 );  /* Register numbers are always positive */
  assert( iCol>=-1 && iCol<32768 );  /* Finite column numbers */

  /* First replace any existing entry */
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
      cacheEntryClear(pParse, p);
      p->iLevel = pParse->iCacheLevel;
      p->iReg = iReg;
      p->affChange = 0;
      p->lru = pParse->iCacheCnt++;
      return;
    }
  }


  /* Find an empty slot and replace it */
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->iReg==0 ){
      p->iLevel = pParse->iCacheLevel;
      p->iTable = iTab;
      p->iColumn = iCol;
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  idxLru = -1;
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->lru<minLru ){
      idxLru = i;
      minLru = p->lru;
    }
  }
  if( idxLru>=0 ){
    p = &pParse->aColCache[idxLru];
    p->iLevel = pParse->iCacheLevel;
    p->iTable = iTab;
    p->iColumn = iCol;
    p->iReg = iReg;
    p->affChange = 0;
    p->tempReg = 0;







|







1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
  idxLru = -1;
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->lru<minLru ){
      idxLru = i;
      minLru = p->lru;
    }
  }
  if( ALWAYS(idxLru>=0) ){
    p = &pParse->aColCache[idxLru];
    p->iLevel = pParse->iCacheLevel;
    p->iTable = iTab;
    p->iColumn = iCol;
    p->iReg = iReg;
    p->affChange = 0;
    p->tempReg = 0;
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
  Vdbe *v = pParse->pVdbe;
  int i;
  struct yColCache *p;

  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn
           && (!p->affChange || allowAffChng) ){
#if 0
      sqlite3VdbeAddOp0(v, OP_Noop);
      VdbeComment((v, "OPT: tab%d.col%d -> r%d", iTable, iColumn, p->iReg));
#endif
      p->lru = pParse->iCacheCnt++;
      sqlite3ExprCachePinRegister(pParse, p->iReg);
      return p->iReg;
    }
  }  
  assert( v!=0 );
  if( iColumn<0 ){
    sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg);
  }else if( pTab==0 ){
    sqlite3VdbeAddOp3(v, OP_Column, iTable, iColumn, iReg);
  }else{
    int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
    sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);
    sqlite3ColumnDefault(v, pTab, iColumn);
#ifndef SQLITE_OMIT_FLOATING_POINT
    if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){
      sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
    }







<
<
<
<








|
<
<







1909
1910
1911
1912
1913
1914
1915




1916
1917
1918
1919
1920
1921
1922
1923
1924


1925
1926
1927
1928
1929
1930
1931
  Vdbe *v = pParse->pVdbe;
  int i;
  struct yColCache *p;

  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn
           && (!p->affChange || allowAffChng) ){




      p->lru = pParse->iCacheCnt++;
      sqlite3ExprCachePinRegister(pParse, p->iReg);
      return p->iReg;
    }
  }  
  assert( v!=0 );
  if( iColumn<0 ){
    sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg);
  }else if( ALWAYS(pTab!=0) ){


    int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
    sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);
    sqlite3ColumnDefault(v, pTab, iColumn);
#ifndef SQLITE_OMIT_FLOATING_POINT
    if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){
      sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
    }
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
/*
** Generate code to move content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
*/
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
  int i;
  struct yColCache *p;
  if( iFrom==iTo ) return;
  sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    int x = p->iReg;
    if( x>=iFrom && x<iFrom+nReg ){
      p->iReg += iTo-iFrom;
    }
  }
}

/*
** Generate code to copy content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1.
*/
void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
  int i;
  if( iFrom==iTo ) return;
  for(i=0; i<nReg; i++){
    sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i);
  }
}

/*
** Return true if any register in the range iFrom..iTo (inclusive)







|















|







1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
/*
** Generate code to move content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
*/
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
  int i;
  struct yColCache *p;
  if( NEVER(iFrom==iTo) ) return;
  sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
  for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
    int x = p->iReg;
    if( x>=iFrom && x<iFrom+nReg ){
      p->iReg += iTo-iFrom;
    }
  }
}

/*
** Generate code to copy content from registers iFrom...iFrom+nReg-1
** over to iTo..iTo+nReg-1.
*/
void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
  int i;
  if( NEVER(iFrom==iTo) ) return;
  for(i=0; i<nReg; i++){
    sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i);
  }
}

/*
** Return true if any register in the range iFrom..iTo (inclusive)
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025

2026
2027

2028
2029
2030
2031
2032
2033
2034
2035
2036
2037

/*
** If the last instruction coded is an ephemeral copy of any of
** the registers in the nReg registers beginning with iReg, then
** convert the last instruction from OP_SCopy to OP_Copy.
*/
void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
  int addr;
  VdbeOp *pOp;
  Vdbe *v;


  v = pParse->pVdbe;
  addr = sqlite3VdbeCurrentAddr(v);

  pOp = sqlite3VdbeGetOp(v, addr-1);
  assert( pOp || pParse->db->mallocFailed );
  if( pOp && pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
    pOp->opcode = OP_Copy;
  }
}

/*
** Generate code to store the value of the iAlias-th alias in register
** target.  The first time this is called, pExpr is evaluated to compute







<



>

<
>
|
|
|







2011
2012
2013
2014
2015
2016
2017

2018
2019
2020
2021
2022

2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033

/*
** If the last instruction coded is an ephemeral copy of any of
** the registers in the nReg registers beginning with iReg, then
** convert the last instruction from OP_SCopy to OP_Copy.
*/
void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){

  VdbeOp *pOp;
  Vdbe *v;

  assert( pParse->db->mallocFailed==0 );
  v = pParse->pVdbe;

  assert( v!=0 );
  pOp = sqlite3VdbeGetOp(v, -1);
  assert( pOp!=0 );
  if( pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
    pOp->opcode = OP_Copy;
  }
}

/*
** Generate code to store the value of the iAlias-th alias in register
** target.  The first time this is called, pExpr is evaluated to compute
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106



2107
2108
2109
2110
2111
2112
2113
int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
  Vdbe *v = pParse->pVdbe;  /* The VM under construction */
  int op;                   /* The opcode being coded */
  int inReg = target;       /* Results stored in register inReg */
  int regFree1 = 0;         /* If non-zero free this temporary register */
  int regFree2 = 0;         /* If non-zero free this temporary register */
  int r1, r2, r3, r4;       /* Various register numbers */
  sqlite3 *db;

  db = pParse->db;
  assert( v!=0 || db->mallocFailed );
  assert( target>0 && target<=pParse->nMem );
  if( v==0 ) return 0;




  if( pExpr==0 ){
    op = TK_NULL;
  }else{
    op = pExpr->op;
  }
  switch( op ){







|

<
<

|
>
>
>







2090
2091
2092
2093
2094
2095
2096
2097
2098


2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
  Vdbe *v = pParse->pVdbe;  /* The VM under construction */
  int op;                   /* The opcode being coded */
  int inReg = target;       /* Results stored in register inReg */
  int regFree1 = 0;         /* If non-zero free this temporary register */
  int regFree2 = 0;         /* If non-zero free this temporary register */
  int r1, r2, r3, r4;       /* Various register numbers */
  sqlite3 *db = pParse->db; /* The database connection */



  assert( target>0 && target<=pParse->nMem );
  if( v==0 ){
    assert( pParse->db->mallocFailed );
    return 0;
  }

  if( pExpr==0 ){
    op = TK_NULL;
  }else{
    op = pExpr->op;
  }
  switch( op ){
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
      assert( z[n]=='\'' );
      zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
      sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
      break;
    }
#endif
    case TK_VARIABLE: {
      int iPrior;
      VdbeOp *pOp;
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      assert( pExpr->u.zToken!=0 );
      assert( pExpr->u.zToken[0]!=0 );
      if( pExpr->u.zToken[1]==0
         && (iPrior = sqlite3VdbeCurrentAddr(v)-1)>=0
         && (pOp = sqlite3VdbeGetOp(v, iPrior))->opcode==OP_Variable
         && pOp->p1+pOp->p3==pExpr->iTable
         && pOp->p2+pOp->p3==target
         && pOp->p4.z==0
      ){
        /* If the previous instruction was a copy of the previous unnamed
        ** parameter into the previous register, then simply increment the
        ** repeat count on the prior instruction rather than making a new







<





<
|







2166
2167
2168
2169
2170
2171
2172

2173
2174
2175
2176
2177

2178
2179
2180
2181
2182
2183
2184
2185
      assert( z[n]=='\'' );
      zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
      sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
      break;
    }
#endif
    case TK_VARIABLE: {

      VdbeOp *pOp;
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      assert( pExpr->u.zToken!=0 );
      assert( pExpr->u.zToken[0]!=0 );
      if( pExpr->u.zToken[1]==0

         && (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable
         && pOp->p1+pOp->p3==pExpr->iTable
         && pOp->p2+pOp->p3==target
         && pOp->p4.z==0
      ){
        /* If the previous instruction was a copy of the previous unnamed
        ** parameter into the previous register, then simply increment the
        ** repeat count on the prior instruction rather than making a new
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
      Vdbe *v = sqlite3GetVdbe(pParse);
      if( iReg!=target+i ){
        sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i);
      }
    }else{
      sqlite3ExprCode(pParse, pItem->pExpr, target+i);
    }
    if( doHardCopy ){
      sqlite3ExprHardCopy(pParse, target, n);
    }
  }
  return n;
}

/*







|







2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
      Vdbe *v = sqlite3GetVdbe(pParse);
      if( iReg!=target+i ){
        sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i);
      }
    }else{
      sqlite3ExprCode(pParse, pItem->pExpr, target+i);
    }
    if( doHardCopy && !pParse->db->mallocFailed ){
      sqlite3ExprHardCopy(pParse, target, n);
    }
  }
  return n;
}

/*
Changes to src/insert.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.267 2009/05/04 11:42:30 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** Generate code that will open a table for reading.
*/
void sqlite3OpenTable(







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.268 2009/05/29 19:00:13 drh Exp $
*/
#include "sqliteInt.h"

/*
** Generate code that will open a table for reading.
*/
void sqlite3OpenTable(
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
      if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
      }else if( pSelect ){
        sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid);
      }else{
        VdbeOp *pOp;
        sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
        pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
        if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
          appendFlag = 1;
          pOp->opcode = OP_NewRowid;
          pOp->p1 = baseCur;
          pOp->p2 = regRowid;
          pOp->p3 = regAutoinc;
        }







|







858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
      if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
      }else if( pSelect ){
        sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid);
      }else{
        VdbeOp *pOp;
        sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
        pOp = sqlite3VdbeGetOp(v, -1);
        if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
          appendFlag = 1;
          pOp->opcode = OP_NewRowid;
          pOp->p1 = baseCur;
          pOp->p2 = regRowid;
          pOp->p3 = regAutoinc;
        }
Changes to src/vdbeaux.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.457 2009/05/06 18:57:10 shane Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"



/*







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.458 2009/05/29 19:00:13 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"



/*
614
615
616
617
618
619
620
621







622
623

624

625



626

627
628
629
630
631
632
633
    *pz = sqlite3VMPrintf(p->db, zFormat, ap);
    va_end(ap);
  }
}
#endif  /* NDEBUG */

/*
** Return the opcode for a given address.







*/
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){

  assert( p->magic==VDBE_MAGIC_INIT );

  assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );



  return ((addr>=0 && addr<p->nOp)?(&p->aOp[addr]):0);

}

#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.







|
>
>
>
>
>
>
>


>

>

>
>
>
|
>







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
    *pz = sqlite3VMPrintf(p->db, zFormat, ap);
    va_end(ap);
  }
}
#endif  /* NDEBUG */

/*
** Return the opcode for a given address.  If the address is -1, then
** return the most recently inserted opcode.
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned.  That opcode
** is readable and writable, but it has no effect.  The return of a dummy
** opcode allows the call to continue functioning after a OOM fault without
** having to check to see if the return from this routine is a valid pointer.
*/
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
  static VdbeOp dummy;
  assert( p->magic==VDBE_MAGIC_INIT );
  if( addr<0 ) addr = p->nOp - 1;
  assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
  if( p->db->mallocFailed ){
    return &dummy;
  }else{
    return &p->aOp[addr];
  }
}

#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
     || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.