SQLite

Check-in [d9ac6beef5]
Login

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

Overview
Comment:Some modifications to insert.c to work without using the stack. (CVS 4678)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d9ac6beef538376d0ea0a1daa95cf1dfe36143cf
User & Date: danielk1977 2008-01-04 19:10:29.000
Context
2008-01-04
19:12
Fix mkopcodeh.awk so that it works on a mac. (CVS 4679) (check-in: 59d3dfa41f user: drh tags: trunk)
19:10
Some modifications to insert.c to work without using the stack. (CVS 4678) (check-in: d9ac6beef5 user: danielk1977 tags: trunk)
16:50
Replace the NOPUSH_MASKs with a bit-vector mechanism that can contain several different properties about each opcode. (CVS 4677) (check-in: 042dcb9621 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to mkopcodeh.awk.
53
54
55
56
57
58
59

60
61
62
63
64
65
66
  out1[name] = 0
  out2[name] = 0
  out3[name] = 0
  jump[name] = 0
  in1[name] = 0
  in2[name] = 0
  in3[name] = 0

  for(i=3; i<NF; i++){
    if($i=="same" && $(i+1)=="as"){
      sym = $(i+2)
      sub(/,/,"",sym)
      op[name] = tk[sym]
      used[op[name]] = 1
      sameas[op[name]] = sym







>







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  out1[name] = 0
  out2[name] = 0
  out3[name] = 0
  jump[name] = 0
  in1[name] = 0
  in2[name] = 0
  in3[name] = 0
  nopush[name] = 0
  for(i=3; i<NF; i++){
    if($i=="same" && $(i+1)=="as"){
      sym = $(i+2)
      sub(/,/,"",sym)
      op[name] = tk[sym]
      used[op[name]] = 1
      sameas[op[name]] = sym
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  #  bit 4:     input on P1
  #  bit 5:     input on P2
  #  bit 6:     input on P3
  #  bit 7:     pushes a result onto stack
  #
  for(i=0; i<=max; i++) bv[i] = 0;
  for(name in op){
    x = op[name]
    if( jump[name] ) bv[x] += 0x01;
    if( out1[name] ) bv[x] += 0x02;
    if( out2[name] ) bv[x] += 0x04;
    if( out3[name] ) bv[x] += 0x08;
    if( in1[name] ) bv[x] += 0x10;
    if( in2[name] ) bv[x] += 0x20;
    if( in3[name] ) bv[x] += 0x40;
    if( !nopush[name] ) bv[x] += 0x80;
  }
  print "\n"
  print "/* Properties such as \"out2\" or \"jump\" that are specified in"
  print "** comments following the "case" for each opcode in the vdbe.c"
  print "** are encoded into bitvectors as follows:"
  print "*/"
  print "#define OPFLG_JUMP     0x01    /* jump:  P2 holds a jump target */"







<







|







128
129
130
131
132
133
134

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  #  bit 4:     input on P1
  #  bit 5:     input on P2
  #  bit 6:     input on P3
  #  bit 7:     pushes a result onto stack
  #
  for(i=0; i<=max; i++) bv[i] = 0;
  for(name in op){

    if( jump[name] ) bv[x] += 0x01;
    if( out1[name] ) bv[x] += 0x02;
    if( out2[name] ) bv[x] += 0x04;
    if( out3[name] ) bv[x] += 0x08;
    if( in1[name] ) bv[x] += 0x10;
    if( in2[name] ) bv[x] += 0x20;
    if( in3[name] ) bv[x] += 0x40;
    if( 0 == nopush[name] ) bv[x] = bv[x] + 0x80;
  }
  print "\n"
  print "/* Properties such as \"out2\" or \"jump\" that are specified in"
  print "** comments following the "case" for each opcode in the vdbe.c"
  print "** are encoded into bitvectors as follows:"
  print "*/"
  print "#define OPFLG_JUMP     0x01    /* jump:  P2 holds a jump target */"
Changes to src/delete.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
** in order to generate code for DELETE FROM statements.
**
** $Id: delete.c,v 1.146 2008/01/04 13:57:26 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables
** are found, return a pointer to the last table.







|







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
** in order to generate code for DELETE FROM statements.
**
** $Id: delete.c,v 1.147 2008/01/04 19:10:29 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables
** are found, return a pointer to the last table.
86
87
88
89
90
91
92








93
94
95
96
97
98
99
  Vdbe *v = sqlite3GetVdbe(p);
  assert(v);
  p->nMem += nVal;
  for(i=nVal-1; i>=0; i--){
    sqlite3VdbeAddOp2(v, OP_MemStore, iRet+i, 1);
  }
  return iRet;








}

/*
** Generate code that will open a table for reading.
*/
void sqlite3OpenTable(
  Parse *p,       /* Generate code into this VDBE */







>
>
>
>
>
>
>
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  Vdbe *v = sqlite3GetVdbe(p);
  assert(v);
  p->nMem += nVal;
  for(i=nVal-1; i>=0; i--){
    sqlite3VdbeAddOp2(v, OP_MemStore, iRet+i, 1);
  }
  return iRet;
}
void sqlite3RegToStack(Parse *p, int iReg, int nVal){
  int i;
  Vdbe *v = sqlite3GetVdbe(p);
  assert(v);
  for(i=0; i<nVal; i++){
    sqlite3VdbeAddOp2(v, OP_MemLoad, iReg+i, 0);
  }
}

/*
** Generate code that will open a table for reading.
*/
void sqlite3OpenTable(
  Parse *p,       /* Generate code into this VDBE */
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.209 2008/01/04 13:24:29 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** Set P4 of the most recently inserted opcode to a column affinity
** string for index pIdx. A column affinity string has one character
** for each column in the table, according to the affinity of the column:







|







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.210 2008/01/04 19:10:29 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** Set P4 of the most recently inserted opcode to a column affinity
** string for index pIdx. A column affinity string has one character
** for each column in the table, according to the affinity of the column:
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
** Update the maximum rowid for an autoincrement calculation.
**
** This routine should be called when the top of the stack holds a
** new rowid that is about to be inserted.  If that new rowid is
** larger than the maximum rowid in the memId memory cell, then the
** memory cell is updated.  The stack is unchanged.
*/
static void autoIncStep(Parse *pParse, int memId){
  if( memId>0 ){
    sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, 0);
  }
}

/*
** After doing one or more inserts, the maximum rowid is stored
** in mem[memId].  Generate code to write this value back into the
** the sqlite_sequence table.







|

|







185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
** Update the maximum rowid for an autoincrement calculation.
**
** This routine should be called when the top of the stack holds a
** new rowid that is about to be inserted.  If that new rowid is
** larger than the maximum rowid in the memId memory cell, then the
** memory cell is updated.  The stack is unchanged.
*/
static void autoIncStep(Parse *pParse, int memId, int iRowid){
  if( memId>0 ){
    sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, iRowid);
  }
}

/*
** After doing one or more inserts, the maximum rowid is stored
** in mem[memId].  Generate code to write this value back into the
** the sqlite_sequence table.
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
}
#else
/*
** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
** above are all no-ops
*/
# define autoIncBegin(A,B,C) (0)
# define autoIncStep(A,B)
# define autoIncEnd(A,B,C,D)
#endif /* SQLITE_OMIT_AUTOINCREMENT */


/* Forward declaration */
static int xferOptimization(
  Parse *pParse,        /* Parser context */







|







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
}
#else
/*
** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
** above are all no-ops
*/
# define autoIncBegin(A,B,C) (0)
# define autoIncStep(A,B,C)
# define autoIncEnd(A,B,C,D)
#endif /* SQLITE_OMIT_AUTOINCREMENT */


/* Forward declaration */
static int xferOptimization(
  Parse *pParse,        /* Parser context */
712
713
714
715
716
717
718




719
720
721
722
723
724
725
726


727
728
729
730
731
732
733
734
735
736




737
738
739
740
741
742
743
744
745
746
747
748
749
750
751

752
753
754
755
756
757
758
759
760

761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787


788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804

805
806
807
808
809
810
811

  /* Push the record number for the new entry onto the stack.  The
  ** record number is a randomly generate integer created by NewRowid
  ** except when the table has an INTEGER PRIMARY KEY column, in which
  ** case the record number is the same as that column. 
  */
  if( !isView ){




    if( IsVirtual(pTab) ){
      /* The row that the VUpdate opcode will delete:  none */
      sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
    }
    if( keyColumn>=0 ){
      if( useTempTable ){
        sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn);
      }else if( pSelect ){


        sqlite3VdbeAddOp2(v, OP_Dup, nColumn - keyColumn - 1, 1);
      }else{
        VdbeOp *pOp;
        sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
        pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
        if( pOp && pOp->opcode==OP_Null ){
          appendFlag = 1;
          pOp->opcode = OP_NewRowid;
          pOp->p1 = base;
          pOp->p2 = counterMem;




        }
      }
      /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
      ** to generate a unique primary key value.
      */
      if( !appendFlag ){
        sqlite3VdbeAddOp2(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
        sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
        sqlite3VdbeAddOp2(v, OP_NewRowid, base, counterMem);
        sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0);
      }
    }else if( IsVirtual(pTab) ){
      sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
    }else{
      sqlite3VdbeAddOp2(v, OP_NewRowid, base, counterMem);

      appendFlag = 1;
    }
    autoIncStep(pParse, counterMem);

    /* Push onto the stack, data for all columns of the new entry, beginning
    ** with the first column.
    */
    nHidden = 0;
    for(i=0; i<pTab->nCol; i++){

      if( i==pTab->iPKey ){
        /* The value of the INTEGER PRIMARY KEY column is always a NULL.
        ** Whenever this column is read, the record number will be substituted
        ** in its place.  So will fill this column with a NULL to avoid
        ** taking up data space with information that will never be used. */
        sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
        continue;
      }
      if( pColumn==0 ){
        if( IsHiddenColumn(&pTab->aCol[i]) ){
          assert( IsVirtual(pTab) );
          j = -1;
          nHidden++;
        }else{
          j = i - nHidden;
        }
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
      }
      if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
      }else if( useTempTable ){
        sqlite3VdbeAddOp2(v, OP_Column, srcTab, j); 
      }else if( pSelect ){
        sqlite3VdbeAddOp2(v, OP_Dup, i+nColumn-j+IsVirtual(pTab), 1);


      }else{
        sqlite3ExprCode(pParse, pList->a[j].pExpr, 0);
      }
    }

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */
#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( IsVirtual(pTab) ){
      int iReg = sqlite3StackToReg(pParse, pTab->nCol+2);
      pParse->pVirtualLock = pTab;
      sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, iReg,
                     (const char*)pTab->pVtab, P4_VTAB);
    }else
#endif
    {

      sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
                                     0, onError, endOfLoop);
      sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
                            (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
                            appendFlag);
    }
  }







>
>
>
>

|
|



|

>
>
|









>
>
>
>






|
|
|
|


|


>


|






>





|
















|

|

|
>
>

|








<






>







712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811

812
813
814
815
816
817
818
819
820
821
822
823
824
825

  /* Push the record number for the new entry onto the stack.  The
  ** record number is a randomly generate integer created by NewRowid
  ** except when the table has an INTEGER PRIMARY KEY column, in which
  ** case the record number is the same as that column. 
  */
  if( !isView ){
    int iReg = pParse->nMem+1;
    int iRowid = iReg+(IsVirtual(pTab)?1:0);
    pParse->nMem += pTab->nCol + (IsVirtual(pTab)?2:1);

    if( IsVirtual(pTab) ){
      /* The row that the VUpdate opcode will delete: none */
      sqlite3VdbeAddOp2(v, OP_MemNull, 0, iReg);
    }
    if( keyColumn>=0 ){
      if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, iRowid);
      }else if( pSelect ){
        sqlite3VdbeAddOp3(v, OP_Dup, nColumn - keyColumn - 1, 1, iRowid);
        /* TODO: Avoid this use of the stack. */
        sqlite3VdbeAddOp2(v, OP_MemStore, iRowid, 1);
      }else{
        VdbeOp *pOp;
        sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
        pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
        if( pOp && pOp->opcode==OP_Null ){
          appendFlag = 1;
          pOp->opcode = OP_NewRowid;
          pOp->p1 = base;
          pOp->p2 = counterMem;
          pOp->p3 = iRowid;
        }else{
          /* TODO: Avoid this use of the stack. */
          sqlite3VdbeAddOp2(v, OP_MemStore, iRowid, 1);
        }
      }
      /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
      ** to generate a unique primary key value.
      */
      if( !appendFlag ){
        sqlite3VdbeAddOp2(v, OP_IfMemNull, iRowid, sqlite3VdbeCurrentAddr(v)+2);
        sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2);
        sqlite3VdbeAddOp3(v, OP_NewRowid, base, counterMem, iRowid);
        sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, iRowid);
      }
    }else if( IsVirtual(pTab) ){
      sqlite3VdbeAddOp2(v, OP_MemNull, 0, iRowid);
    }else{
      sqlite3VdbeAddOp2(v, OP_NewRowid, base, counterMem);
      sqlite3VdbeAddOp2(v, OP_MemStore, iRowid, 1);
      appendFlag = 1;
    }
    autoIncStep(pParse, counterMem, iRowid);

    /* Push onto the stack, data for all columns of the new entry, beginning
    ** with the first column.
    */
    nHidden = 0;
    for(i=0; i<pTab->nCol; i++){
      int iRegStore = iRowid+1+i;
      if( i==pTab->iPKey ){
        /* The value of the INTEGER PRIMARY KEY column is always a NULL.
        ** Whenever this column is read, the record number will be substituted
        ** in its place.  So will fill this column with a NULL to avoid
        ** taking up data space with information that will never be used. */
        sqlite3VdbeAddOp2(v, OP_MemNull, 0, iRegStore);
        continue;
      }
      if( pColumn==0 ){
        if( IsHiddenColumn(&pTab->aCol[i]) ){
          assert( IsVirtual(pTab) );
          j = -1;
          nHidden++;
        }else{
          j = i - nHidden;
        }
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
      }
      if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
      }else if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); 
      }else if( pSelect ){
        sqlite3VdbeAddOp2(v, OP_Dup, nColumn-j-1, 1);
        /* TODO: Avoid this use of the stack */
        sqlite3VdbeAddOp2(v, OP_MemStore, iRegStore, 1);
      }else{
        sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
      }
    }

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */
#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( IsVirtual(pTab) ){

      pParse->pVirtualLock = pTab;
      sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, iReg,
                     (const char*)pTab->pVtab, P4_VTAB);
    }else
#endif
    {
      sqlite3RegToStack(pParse, iReg, pTab->nCol+1);
      sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
                                     0, onError, endOfLoop);
      sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
                            (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
                            appendFlag);
    }
  }
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
  if( pDest->iPKey>=0 ){
    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
    sqlite3VdbeAddOp2(v, OP_Dup, 0, 0);
    addr2 = sqlite3VdbeAddOp2(v, OP_NotExists, iDest, 0);
    sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
                      "PRIMARY KEY must be unique", P4_STATIC);
    sqlite3VdbeJumpHere(v, addr2);
    autoIncStep(pParse, counterMem);
  }else if( pDest->pIndex==0 ){
    addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, 0);
  }else{
    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
    assert( pDest->autoInc==0 );
  }
  sqlite3VdbeAddOp2(v, OP_RowData, iSrc, 0);







|







1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
  if( pDest->iPKey>=0 ){
    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
    sqlite3VdbeAddOp2(v, OP_Dup, 0, 0);
    addr2 = sqlite3VdbeAddOp2(v, OP_NotExists, iDest, 0);
    sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
                      "PRIMARY KEY must be unique", P4_STATIC);
    sqlite3VdbeJumpHere(v, addr2);
    autoIncStep(pParse, counterMem, 0);
  }else if( pDest->pIndex==0 ){
    addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, 0);
  }else{
    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
    assert( pDest->autoInc==0 );
  }
  sqlite3VdbeAddOp2(v, OP_RowData, iSrc, 0);
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.637 2008/01/04 13:24:29 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false.  Macro likely() surrounds













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.638 2008/01/04 19:10:29 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false.  Macro likely() surrounds
1915
1916
1917
1918
1919
1920
1921

1922
1923
1924
1925
1926
1927
1928
int sqlite3OpenTempDatabase(Parse *);

void sqlite3StrAccumAppend(StrAccum*,const char*,int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumReset(StrAccum*);
void sqlite3CodeInsert(Parse *, int, u8);
int sqlite3StackToReg(Parse *, int);


/*
** The interface to the LEMON-generated parser
*/
void *sqlite3ParserAlloc(void*(*)(size_t));
void sqlite3ParserFree(void*, void(*)(void*));
void sqlite3Parser(void*, int, Token, Parse*);







>







1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
int sqlite3OpenTempDatabase(Parse *);

void sqlite3StrAccumAppend(StrAccum*,const char*,int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumReset(StrAccum*);
void sqlite3CodeInsert(Parse *, int, u8);
int sqlite3StackToReg(Parse *, int);
void sqlite3RegToStack(Parse *, int, int);

/*
** The interface to the LEMON-generated parser
*/
void *sqlite3ParserAlloc(void*(*)(size_t));
void sqlite3ParserFree(void*, void(*)(void*));
void sqlite3Parser(void*, int, Token, Parse*);
Changes to src/update.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 UPDATE statements.
**
** $Id: update.c,v 1.156 2008/01/04 13:57:26 danielk1977 Exp $
*/
#include "sqliteInt.h"

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Forward declaration */
static void updateVirtualTable(
  Parse *pParse,       /* The parsing context */







|







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 UPDATE statements.
**
** $Id: update.c,v 1.157 2008/01/04 19:10:29 danielk1977 Exp $
*/
#include "sqliteInt.h"

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Forward declaration */
static void updateVirtualTable(
  Parse *pParse,       /* The parsing context */
588
589
590
591
592
593
594

595

596
597
598
599
600
601
602
  Vdbe *v = pParse->pVdbe;  /* Virtual machine under construction */
  ExprList *pEList = 0;     /* The result set of the SELECT statement */
  Select *pSelect = 0;      /* The SELECT statement */
  Expr *pExpr;              /* Temporary expression */
  int ephemTab;             /* Table holding the result of the SELECT */
  int i;                    /* Loop counter */
  int addr;                 /* Address of top of loop */

  sqlite3 *db = pParse->db; /* Database connection */

  SelectDest dest = {SRT_Table, 0, 0};

  /* Construct the SELECT statement that will find the new values for
  ** all updated rows. 
  */
  pEList = sqlite3ExprListAppend(pParse, 0, 
                                 sqlite3CreateIdExpr(pParse, "_rowid_"), 0);







>

>







588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
  Vdbe *v = pParse->pVdbe;  /* Virtual machine under construction */
  ExprList *pEList = 0;     /* The result set of the SELECT statement */
  Select *pSelect = 0;      /* The SELECT statement */
  Expr *pExpr;              /* Temporary expression */
  int ephemTab;             /* Table holding the result of the SELECT */
  int i;                    /* Loop counter */
  int addr;                 /* Address of top of loop */
  int iReg;                 /* First register in set passed to OP_VUpdate */
  sqlite3 *db = pParse->db; /* Database connection */
  const char *pVtab = (const char*)pTab->pVtab;
  SelectDest dest = {SRT_Table, 0, 0};

  /* Construct the SELECT statement that will find the new values for
  ** all updated rows. 
  */
  pEList = sqlite3ExprListAppend(pParse, 0, 
                                 sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
623
624
625
626
627
628
629
630
631
632
633

634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));

  /* fill the ephemeral table 
  */
  dest.iParm = ephemTab;
  sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);

  /*
  ** Generate code to scan the ephemeral table and call VDelete and
  ** VInsert
  */

  sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
  addr = sqlite3VdbeCurrentAddr(v);
  sqlite3VdbeAddOp2(v, OP_Column,  ephemTab, 0);
  if( pRowid ){
    sqlite3VdbeAddOp2(v, OP_Column, ephemTab, 1);
  }else{
    sqlite3VdbeAddOp2(v, OP_Dup, 0, 0);
  }
  for(i=0; i<pTab->nCol; i++){
    sqlite3VdbeAddOp2(v, OP_Column, ephemTab, i+1+(pRowid!=0));
  }
  pParse->pVirtualLock = pTab;
  sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, 
      sqlite3StackToReg(pParse, pTab->nCol+2), 
      (const char*)pTab->pVtab, P4_VTAB
  );
  sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr);
  sqlite3VdbeJumpHere(v, addr-1);
  sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);

  /* Cleanup */
  sqlite3SelectDelete(pSelect);  
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */







<
|
|
<
>


|
<
|
<
<
<

|


|
<
<
<








625
626
627
628
629
630
631

632
633

634
635
636
637

638



639
640
641
642
643



644
645
646
647
648
649
650
651
  sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));

  /* fill the ephemeral table 
  */
  dest.iParm = ephemTab;
  sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);


  /* Generate code to scan the ephemeral table and call VUpdate. */
  iReg = ++pParse->nMem;

  pParse->nMem += pTab->nCol+1;
  sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
  addr = sqlite3VdbeCurrentAddr(v);
  sqlite3VdbeAddOp3(v, OP_Column,  ephemTab, 0, iReg);

  sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);



  for(i=0; i<pTab->nCol; i++){
    sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
  }
  pParse->pVirtualLock = pTab;
  sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVtab, P4_VTAB);



  sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr);
  sqlite3VdbeJumpHere(v, addr-1);
  sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);

  /* Cleanup */
  sqlite3SelectDelete(pSelect);  
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.677 2008/01/04 16:50:09 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.678 2008/01/04 19:10:29 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
587
588
589
590
591
592
593

594
595
596
597
598
599
600
    /* This is to check to make sure that the OPFLG_PUSH property
    ** is set correctly on all opcodes.
    */ 
    pStackLimit = pTos;
    if( sqlite3VdbeOpcodeHasProperty(pOp->opcode, OPFLG_PUSH) ){
      pStackLimit++;
    }

#endif

    switch( pOp->opcode ){

/*****************************************************************************
** What follows is a massive switch statement where each case implements a
** separate instruction in the virtual machine.  If we follow the usual







>







587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
    /* This is to check to make sure that the OPFLG_PUSH property
    ** is set correctly on all opcodes.
    */ 
    pStackLimit = pTos;
    if( sqlite3VdbeOpcodeHasProperty(pOp->opcode, OPFLG_PUSH) ){
      pStackLimit++;
    }
    assert( pTos>=&p->aStack[-1] && pTos<=pStackLimit );
#endif

    switch( pOp->opcode ){

/*****************************************************************************
** What follows is a massive switch statement where each case implements a
** separate instruction in the virtual machine.  If we follow the usual
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538



1539
1540

1541

1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
  }
  Release(pTos);
  pTos->u.i = v;
  pTos->flags = MEM_Int;
  break;
}

/* Opcode: MustBeInt P1 P2 *
** 
** Force the top of the stack to be an integer.  If the top of the
** stack is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
**
** If the top of the stack is not an integer and P2 is not zero and
** P1 is 1, then the stack is popped.  In all other cases, the depth
** of the stack is unchanged.



*/
case OP_MustBeInt: {            /* no-push, jump */

  assert( pTos>=p->aStack );

  applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
  if( (pTos->flags & MEM_Int)==0 ){
    if( pOp->p2==0 ){
      rc = SQLITE_MISMATCH;
      goto abort_due_to_error;
    }else{
      if( pOp->p1 ) popStack(&pTos, 1);
      pc = pOp->p2 - 1;
    }
  }else{
    Release(pTos);
    pTos->flags = MEM_Int;
  }
  break;
}

/* Opcode: RealAffinity P1 * *
**
** If register P1 holds an integer convert it to a real value.







|









>
>
>


>
|
>
|
|



|




|
|







1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
  }
  Release(pTos);
  pTos->u.i = v;
  pTos->flags = MEM_Int;
  break;
}

/* Opcode: MustBeInt P1 P2 P3
** 
** Force the top of the stack to be an integer.  If the top of the
** stack is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
**
** If the top of the stack is not an integer and P2 is not zero and
** P1 is 1, then the stack is popped.  In all other cases, the depth
** of the stack is unchanged.
**
** If P3 is not zero, then act on the value in register P3 instead
** of using the stack.
*/
case OP_MustBeInt: {            /* no-push, jump */
  Mem *pMem = ((pOp->p3==0)?pTos:&p->aMem[pOp->p3]);
  assert( pOp->p3 || pTos>=p->aStack );
  assert( pOp->p3>=0 && pOp->p3<=p->nMem );
  applyAffinity(pMem, SQLITE_AFF_NUMERIC, encoding);
  if( (pMem->flags & MEM_Int)==0 ){
    if( pOp->p2==0 ){
      rc = SQLITE_MISMATCH;
      goto abort_due_to_error;
    }else if( pMem==pTos ){
      if( pOp->p1 ) popStack(&pTos, 1);
      pc = pOp->p2 - 1;
    }
  }else{
    Release(pMem);
    pMem->flags = MEM_Int;
  }
  break;
}

/* Opcode: RealAffinity P1 * *
**
** If register P1 holds an integer convert it to a real value.
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
  pTos++;
  pTos->u.i = p->apCsr[i]->seqCount++;
  pTos->flags = MEM_Int;
  break;
}


/* Opcode: NewRowid P1 P2 *
**
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
** The record number is not previously used as a key in the database
** table that cursor P1 points to.  The new record number is pushed 
** onto the stack.
**
** If P2>0 then P2 is a memory cell that holds the largest previously
** generated record number.  No new record numbers are allowed to be less
** than this value.  When this value reaches its maximum, a SQLITE_FULL
** error is generated.  The P2 memory cell is updated with the generated
** record number.  This P2 mechanism is used to help implement the
** AUTOINCREMENT feature.







|




|







3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
  pTos++;
  pTos->u.i = p->apCsr[i]->seqCount++;
  pTos->flags = MEM_Int;
  break;
}


/* Opcode: NewRowid P1 P2 P3
**
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
** The record number is not previously used as a key in the database
** table that cursor P1 points to.  The new record number is pushed 
** onto the stack if P3 is 0 or written to memory cell P3 otherwise.
**
** If P2>0 then P2 is a memory cell that holds the largest previously
** generated record number.  No new record numbers are allowed to be less
** than this value.  When this value reaches its maximum, a SQLITE_FULL
** error is generated.  The P2 memory cell is updated with the generated
** record number.  This P2 mechanism is used to help implement the
** AUTOINCREMENT feature.
3583
3584
3585
3586
3587
3588
3589



3590
3591
3592

3593
3594
3595
3596
3597
3598
3599
        goto abort_due_to_error;
      }
    }
    pC->rowidIsValid = 0;
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }



  pTos++;
  pTos->u.i = v;
  pTos->flags = MEM_Int;

  break;
}

/* Opcode: Insert P1 P2 P3 P4 P5
**
** Write an entry into the table of cursor P1.  A new entry is
** created if it doesn't already exist or the data for an existing







>
>
>
|
|
|
>







3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
        goto abort_due_to_error;
      }
    }
    pC->rowidIsValid = 0;
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }
  if( pOp->p3 ){
    sqlite3VdbeMemSetInt64(&p->aMem[pOp->p3], v);
  }else{
    pTos++;
    pTos->u.i = v;
    pTos->flags = MEM_Int;
  }
  break;
}

/* Opcode: Insert P1 P2 P3 P4 P5
**
** Write an entry into the table of cursor P1.  A new entry is
** created if it doesn't already exist or the data for an existing
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667

4668
4669
4670
4671
4672
4673
4674
4675

4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
  assert( i>0 && i<=p->nMem );
  pTos++;
  sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem);
  break;
}

#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Opcode: MemMax P1 * *
**
** Set the value of memory cell P1 to the maximum of its current value

** and the value on the top of the stack.  The stack is unchanged.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: {        /* no-push */
  int i = pOp->p1;
  Mem *pMem;

  assert( pTos>=p->aStack );
  assert( i>0 && i<=p->nMem );
  pMem = &p->aMem[i];
  sqlite3VdbeMemIntegerify(pMem);
  sqlite3VdbeMemIntegerify(pTos);
  if( pMem->u.i<pTos->u.i){
    pMem->u.i = pTos->u.i;
  }
  break;
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */

/* Opcode: MemIncr P1 P2 *
**







|


>
|







>
|



|
|
|







4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
  assert( i>0 && i<=p->nMem );
  pTos++;
  sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem);
  break;
}

#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Opcode: MemMax P1 P2 *
**
** Set the value of memory cell P1 to the maximum of its current value
** and the value in cell P2, or the value on the top of the stack if P2
** is zero. The stack is unchanged in either case.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: {        /* no-push */
  int i = pOp->p1;
  Mem *pMem;
  Mem *pNew = (pOp->p2?(&p->aMem[pOp->p2]):pTos);
  assert( pOp->p2 || pTos>=p->aStack );
  assert( i>0 && i<=p->nMem );
  pMem = &p->aMem[i];
  sqlite3VdbeMemIntegerify(pMem);
  sqlite3VdbeMemIntegerify(pNew);
  if( pMem->u.i<pNew->u.i){
    pMem->u.i = pNew->u.i;
  }
  break;
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */

/* Opcode: MemIncr P1 P2 *
**
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
** by 6 spaces.  But the left-most 6 spaces have been removed to improve the
** readability.  From this point on down, the normal indentation rules are
** restored.
*****************************************************************************/
    }

    /* Make sure the stack limit was not exceeded */
    assert( pTos<=pStackLimit );

#ifdef VDBE_PROFILE
    {
      long long elapse = hwtime() - start;
      pOp->cycles += elapse;
      pOp->cnt++;
#if 0







|







5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
** by 6 spaces.  But the left-most 6 spaces have been removed to improve the
** readability.  From this point on down, the normal indentation rules are
** restored.
*****************************************************************************/
    }

    /* Make sure the stack limit was not exceeded */
    assert( pTos>=&p->aStack[-1] && pTos<=pStackLimit );

#ifdef VDBE_PROFILE
    {
      long long elapse = hwtime() - start;
      pOp->cycles += elapse;
      pOp->cnt++;
#if 0
Changes to test/autoinc.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2004 November 12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the AUTOINCREMENT features.
#
# $Id: autoinc.test,v 1.10 2007/10/09 08:29:32 danielk1977 Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# If the library is not compiled with autoincrement support then
# skip all tests in this file.













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2004 November 12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the AUTOINCREMENT features.
#
# $Id: autoinc.test,v 1.11 2008/01/04 19:10:29 danielk1977 Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# If the library is not compiled with autoincrement support then
# skip all tests in this file.
236
237
238
239
240
241
242


243
244
245
246
247
248
249
  }
} {t1 1241}

ifcapable tempdb {
  do_test autoinc-2.52 {
    execsql {
      CREATE TEMP TABLE t2 AS SELECT y FROM t1;


      INSERT INTO t1 SELECT NULL, y+4 FROM t2;
      SELECT * FROM t1;
    }
  } {235 1 1235 2 1240 3 1241 4 1242 5 1243 6 1244 7 1245 8}
  do_test autoinc-2.53 {
    execsql {
      SELECT * FROM sqlite_sequence







>
>







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  }
} {t1 1241}

ifcapable tempdb {
  do_test autoinc-2.52 {
    execsql {
      CREATE TEMP TABLE t2 AS SELECT y FROM t1;
    }
    execsql {
      INSERT INTO t1 SELECT NULL, y+4 FROM t2;
      SELECT * FROM t1;
    }
  } {235 1 1235 2 1240 3 1241 4 1242 5 1243 6 1244 7 1245 8}
  do_test autoinc-2.53 {
    execsql {
      SELECT * FROM sqlite_sequence
Changes to test/tester.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.94 2007/10/23 14:49:59 drh Exp $


set tcl_precision 15
set sqlite_pending_byte 0x0010000

# 
# Check the command-line arguments for a default soft-heap-limit.













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.95 2008/01/04 19:10:29 danielk1977 Exp $


set tcl_precision 15
set sqlite_pending_byte 0x0010000

# 
# Check the command-line arguments for a default soft-heap-limit.
234
235
236
237
238
239
240
241
242
243
244


245
246
247
248
249
250
251
  return $r
}

# Do an VDBE code dump on the SQL given
#
proc explain {sql {db db}} {
  puts ""
  puts "addr  opcode        p1       p2     p3             "
  puts "----  ------------  ------  ------  ---------------"
  $db eval "explain $sql" {} {
    puts [format {%-4d  %-12.12s  %-6d  %-6d  %s} $addr $opcode $p1 $p2 $p3]


  }
}

# Another procedure to execute SQL.  This one includes the field
# names in the returned list.
#
proc execsql2 {sql} {







|
|

|
>
>







234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  return $r
}

# Do an VDBE code dump on the SQL given
#
proc explain {sql {db db}} {
  puts ""
  puts "addr  opcode        p1      p2      p3      p4               p5  #"
  puts "----  ------------  ------  ------  ------  ---------------  --  -"
  $db eval "explain $sql" {} {
    puts [format {%-4d  %-12.12s  %-6d  %-6d  %-6d  % -17s %s  %s} \
      $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
    ]
  }
}

# Another procedure to execute SQL.  This one includes the field
# names in the returned list.
#
proc execsql2 {sql} {