/ Check-in [9eb91efd]
Login

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

Overview
Comment:Fixes for new triggers scheme.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:9eb91efda5241609ff18ff15ef5eaa0e86788eab
User & Date: dan 2009-08-30 11:42:52
Context
2009-08-31
05:23
Fix another test problem and some instances where an OOM may cause a segfault. check-in: 31199db0 user: dan tags: trunk
2009-08-30
11:42
Fixes for new triggers scheme. check-in: 9eb91efd user: dan tags: trunk
2009-08-28
18:53
Changes to support recursive triggers. check-in: 9b9c1921 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/delete.c.

404
405
406
407
408
409
410

411
412


413
414
415
416
417
418
419
420
421
422
...
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
      sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);

      /* Populate the OLD.* pseudo-table */
      assert( regOld==iRowid+1 );
      for(i=0; i<pTab->nCol; i++){
        if( mask==0xffffffff || mask&(1<<i) ){
          sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);

        }
      }



      sqlite3CodeRowTrigger(pParse, pTrigger, 
          TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, regOld, OE_Default, addr
      );
    }

    if( !isView ){
      /* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
      if( IsVirtual(pTab) ){
................................................................................
      {
        sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
      }
    }

    /* Code the AFTER triggers. This is a no-op if there are no triggers. */
    sqlite3CodeRowTrigger(pParse, 
      pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, regOld, OE_Default, addr
    );

    /* End of the delete loop */
    sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
    sqlite3VdbeResolveLabel(v, end);

    /* Close the cursors open on the table and its indexes. */







>


>
>


|







 







|







404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
      sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);

      /* Populate the OLD.* pseudo-table */
      assert( regOld==iRowid+1 );
      for(i=0; i<pTab->nCol; i++){
        if( mask==0xffffffff || mask&(1<<i) ){
          sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
          sqlite3ColumnDefault(v, pTab, i, regOld+i);
        }
      }
      sqlite3VdbeAddOp2(v, OP_Affinity, regOld, pTab->nCol);
      sqlite3TableAffinityStr(v, pTab);

      sqlite3CodeRowTrigger(pParse, pTrigger, 
          TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, iRowid, OE_Default, addr
      );
    }

    if( !isView ){
      /* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
      if( IsVirtual(pTab) ){
................................................................................
      {
        sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
      }
    }

    /* Code the AFTER triggers. This is a no-op if there are no triggers. */
    sqlite3CodeRowTrigger(pParse, 
      pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, iRowid, OE_Default, addr
    );

    /* End of the delete loop */
    sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
    sqlite3VdbeResolveLabel(v, end);

    /* Close the cursors open on the table and its indexes. */

Changes to src/expr.c.

86
87
88
89
90
91
92

93

94
95
96
97
98
99
100
....
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564

2565
2566
2567
2568
2569
2570
2571
  CollSeq *pColl = 0;
  Expr *p = pExpr;
  while( ALWAYS(p) ){
    int op;
    pColl = p->pColl;
    if( pColl ) break;
    op = p->op;

    if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER) && p->pTab!=0 ){

      /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
      ** a TK_COLUMN but was previously evaluated and cached in a register */
      const char *zColl;
      int j = p->iColumn;
      if( j>=0 ){
        sqlite3 *db = pParse->db;
        zColl = p->pTab->aCol[j].zColl;
................................................................................
    }
    case TK_UPLUS: {
      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
      break;
    }

    case TK_TRIGGER: {
      sqlite3VdbeAddOp3(v, OP_TriggerVal, pExpr->iColumn, target,pExpr->iTable);
      assert( pExpr->pTab );
      VdbeComment((v, "%s.%s", 
        (pExpr->iTable ? "new" : "old"), 
        (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName)

      ));
      break;
    }


    /*
    ** Form A:







>
|
>







 







|
|
|

|
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
....
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
  CollSeq *pColl = 0;
  Expr *p = pExpr;
  while( ALWAYS(p) ){
    int op;
    pColl = p->pColl;
    if( pColl ) break;
    op = p->op;
    if( p->pTab!=0 && (
        op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER
    )){
      /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
      ** a TK_COLUMN but was previously evaluated and cached in a register */
      const char *zColl;
      int j = p->iColumn;
      if( j>=0 ){
        sqlite3 *db = pParse->db;
        zColl = p->pTab->aCol[j].zColl;
................................................................................
    }
    case TK_UPLUS: {
      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
      break;
    }

    case TK_TRIGGER: {
      int iVal = pExpr->iTable * (pExpr->pTab->nCol+1) + 1 + pExpr->iColumn;
      sqlite3VdbeAddOp2(v, OP_Param, iVal, target);
      VdbeComment((v, "%s.%s -> $%d", 
        (pExpr->iTable ? "new" : "old"), 
        (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName),
	target
      ));
      break;
    }


    /*
    ** Form A:

Changes to src/insert.c.

193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
224
225
226
227
228
229
230



231
232
233
234
235
236
237
...
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
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
....
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
....
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
static int autoIncBegin(
  Parse *pParse,      /* Parsing context */
  int iDb,            /* Index of the database holding pTab */
  Table *pTab         /* The table we are writing to */
){
  int memId = 0;      /* Register holding maximum rowid */
  if( pTab->tabFlags & TF_Autoincrement ){

    AutoincInfo *pInfo;

    pInfo = pParse->pAinc;
    while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
    if( pInfo==0 ){
      pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
      if( pInfo==0 ) return 0;
      pInfo->pNext = pParse->pAinc;
      pParse->pAinc = pInfo;
      pInfo->pTab = pTab;
      pInfo->iDb = iDb;
      pParse->nMem++;                  /* Register to hold name of table */
      pInfo->regCtr = ++pParse->nMem;  /* Max rowid register */
      pParse->nMem++;                  /* Rowid in sqlite_sequence */
    }
    memId = pInfo->regCtr;
  }
  return memId;
}

/*
................................................................................
void sqlite3AutoincrementBegin(Parse *pParse){
  AutoincInfo *p;            /* Information about an AUTOINCREMENT */
  sqlite3 *db = pParse->db;  /* The database connection */
  Db *pDb;                   /* Database only autoinc table */
  int memId;                 /* Register holding max rowid */
  int addr;                  /* A VDBE address */
  Vdbe *v = pParse->pVdbe;   /* VDBE under construction */




  assert( v );   /* We failed long ago if this is not so */
  for(p = pParse->pAinc; p; p = p->pNext){
    pDb = &db->aDb[p->iDb];
    memId = p->regCtr;
    sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
    addr = sqlite3VdbeCurrentAddr(v);
................................................................................
  }
  regData = regRowid+1;

  /* Run the BEFORE and INSTEAD OF triggers, if there are any
  */
  endOfLoop = sqlite3VdbeMakeLabel(v);
  if( tmask & TRIGGER_BEFORE ){
    int regTrigRowid;
    int regCols;

    /* build the NEW.* reference row.  Note that if there is an INTEGER
    ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
    ** translated into a unique ID for the row.  But on a BEFORE trigger,
    ** we do not know what the unique ID will be (because the insert has
    ** not happened yet) so we substitute a rowid of -1
    */
    regTrigRowid = sqlite3GetTempReg(pParse);
    if( keyColumn<0 ){
      sqlite3VdbeAddOp2(v, OP_Integer, -1, regTrigRowid);
    }else{
      int j1;
      if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regTrigRowid);
      }else{
        assert( pSelect==0 );  /* Otherwise useTempTable is true */
        sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regTrigRowid);
      }
      j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regTrigRowid);
      sqlite3VdbeAddOp2(v, OP_Integer, -1, regTrigRowid);
      sqlite3VdbeJumpHere(v, j1);
      sqlite3VdbeAddOp1(v, OP_MustBeInt, regTrigRowid);
    }

    /* Cannot have triggers on a virtual table. If it were possible,
    ** this block would have to account for hidden column.
    */
    assert( !IsVirtual(pTab) );

    /* Create the new column data
    */
    regCols = sqlite3GetTempRange(pParse, pTab->nCol);
    for(i=0; i<pTab->nCol; i++){
      if( pColumn==0 ){
        j = i;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
      }
      if( pColumn && j>=pColumn->nId ){
        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i);
      }else if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); 
      }else{
        assert( pSelect==0 ); /* Otherwise useTempTable is true */
        sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i);
      }
    }

    /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
    ** do not attempt any conversions before assembling the record.
    ** If this is a real table, attempt conversions as required by the
    ** table column affinities.
    */
    if( !isView ){
      sqlite3VdbeAddOp2(v, OP_Affinity, regCols, pTab->nCol);
      sqlite3TableAffinityStr(v, pTab);
    }

    /* Fire BEFORE or INSTEAD OF triggers */
    sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, 
        pTab, regCols, -1, onError, endOfLoop);

    sqlite3ReleaseTempReg(pParse, regTrigRowid);
    sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
  }

  /* 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( (db->flags & SQLITE_CountRows)!=0 ){
    sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
  }

  if( pTrigger ){
    /* Code AFTER triggers */
    sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, 
          pTab, regData, -1, onError, endOfLoop);
  }

  /* The bottom of the main insertion loop, if the data source
  ** is a SELECT statement.
  */
  sqlite3VdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
................................................................................

  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;
  regData = regRowid + 1;


  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      continue;
    }
    onError = pTab->aCol[i].notNull;
................................................................................
      onError = overrideError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }
    
    if( onError!=OE_Replace || pTab->pIndex ){
      if( isUpdate ){
        j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1);
      }
      j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
      switch( onError ){
        default: {
          onError = OE_Abort;
          /* Fall thru into the next case */
        }







>


|




|
|


|
|
|







 







>
>
>







 







|
<







<

|



|


|

|
|

|









<









|

|


|









|





|

<
|







 







|







 







<







 







|







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
...
805
806
807
808
809
810
811
812

813
814
815
816
817
818
819

820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842

843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
882
...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
....
1149
1150
1151
1152
1153
1154
1155

1156
1157
1158
1159
1160
1161
1162
....
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
static int autoIncBegin(
  Parse *pParse,      /* Parsing context */
  int iDb,            /* Index of the database holding pTab */
  Table *pTab         /* The table we are writing to */
){
  int memId = 0;      /* Register holding maximum rowid */
  if( pTab->tabFlags & TF_Autoincrement ){
    Parse *pRoot = (pParse->pRoot ? pParse->pRoot : pParse);
    AutoincInfo *pInfo;

    pInfo = pRoot->pAinc;
    while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
    if( pInfo==0 ){
      pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
      if( pInfo==0 ) return 0;
      pInfo->pNext = pRoot->pAinc;
      pRoot->pAinc = pInfo;
      pInfo->pTab = pTab;
      pInfo->iDb = iDb;
      pRoot->nMem++;                  /* Register to hold name of table */
      pInfo->regCtr = ++pRoot->nMem;  /* Max rowid register */
      pRoot->nMem++;                  /* Rowid in sqlite_sequence */
    }
    memId = pInfo->regCtr;
  }
  return memId;
}

/*
................................................................................
void sqlite3AutoincrementBegin(Parse *pParse){
  AutoincInfo *p;            /* Information about an AUTOINCREMENT */
  sqlite3 *db = pParse->db;  /* The database connection */
  Db *pDb;                   /* Database only autoinc table */
  int memId;                 /* Register holding max rowid */
  int addr;                  /* A VDBE address */
  Vdbe *v = pParse->pVdbe;   /* VDBE under construction */

  /* If currently generating a trigger program, this call is a no-op */
  if( pParse->pTriggerTab ) return;

  assert( v );   /* We failed long ago if this is not so */
  for(p = pParse->pAinc; p; p = p->pNext){
    pDb = &db->aDb[p->iDb];
    memId = p->regCtr;
    sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
    addr = sqlite3VdbeCurrentAddr(v);
................................................................................
  }
  regData = regRowid+1;

  /* Run the BEFORE and INSTEAD OF triggers, if there are any
  */
  endOfLoop = sqlite3VdbeMakeLabel(v);
  if( tmask & TRIGGER_BEFORE ){
    int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1);


    /* build the NEW.* reference row.  Note that if there is an INTEGER
    ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
    ** translated into a unique ID for the row.  But on a BEFORE trigger,
    ** we do not know what the unique ID will be (because the insert has
    ** not happened yet) so we substitute a rowid of -1
    */

    if( keyColumn<0 ){
      sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
    }else{
      int j1;
      if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regCols);
      }else{
        assert( pSelect==0 );  /* Otherwise useTempTable is true */
        sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regCols);
      }
      j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols);
      sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
      sqlite3VdbeJumpHere(v, j1);
      sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols);
    }

    /* Cannot have triggers on a virtual table. If it were possible,
    ** this block would have to account for hidden column.
    */
    assert( !IsVirtual(pTab) );

    /* Create the new column data
    */

    for(i=0; i<pTab->nCol; i++){
      if( pColumn==0 ){
        j = i;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
      }
      if( pColumn && j>=pColumn->nId ){
        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
      }else if( useTempTable ){
        sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); 
      }else{
        assert( pSelect==0 ); /* Otherwise useTempTable is true */
        sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
      }
    }

    /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
    ** do not attempt any conversions before assembling the record.
    ** If this is a real table, attempt conversions as required by the
    ** table column affinities.
    */
    if( !isView ){
      sqlite3VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol);
      sqlite3TableAffinityStr(v, pTab);
    }

    /* Fire BEFORE or INSTEAD OF triggers */
    sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, 
        pTab, -1, regCols-pTab->nCol-1, onError, endOfLoop);


    sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
  }

  /* 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( (db->flags & SQLITE_CountRows)!=0 ){
    sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
  }

  if( pTrigger ){
    /* Code AFTER triggers */
    sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, 
        pTab, -1, regData-2-pTab->nCol, onError, endOfLoop);
  }

  /* The bottom of the main insertion loop, if the data source
  ** is a SELECT statement.
  */
  sqlite3VdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
................................................................................

  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;
  regData = regRowid + 1;


  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      continue;
    }
    onError = pTab->aCol[i].notNull;
................................................................................
      onError = overrideError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }
    
    if( onError!=OE_Replace || pTab->pIndex ){
      if( isUpdate ){
        j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, rowidChng);
      }
      j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
      switch( onError ){
        default: {
          onError = OE_Abort;
          /* Fall thru into the next case */
        }

Changes to src/main.c.

1586
1587
1588
1589
1590
1591
1592



1593
1594
1595
1596
1597
1598
1599
  db->nextPagesize = 0;
  db->flags |= SQLITE_ShortColNames
#if SQLITE_DEFAULT_FILE_FORMAT<4
                 | SQLITE_LegacyFileFmt
#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
                 | SQLITE_LoadExtension



#endif
      ;
  sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3HashInit(&db->aModule);
#endif








>
>
>







1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
  db->nextPagesize = 0;
  db->flags |= SQLITE_ShortColNames
#if SQLITE_DEFAULT_FILE_FORMAT<4
                 | SQLITE_LegacyFileFmt
#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
                 | SQLITE_LoadExtension
#endif
#ifdef SQLITE_DISABLE_RECURSIVE_TRIGGERS
                 | SQLITE_NoRecTriggers
#endif
      ;
  sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3HashInit(&db->aModule);
#endif

Changes to src/pragma.c.

186
187
188
189
190
191
192

193
194
195
196
197
198
199
    /* The following is VERY experimental */
    { "writable_schema",          SQLITE_WriteSchema|SQLITE_RecoveryMode },
    { "omit_readlock",            SQLITE_NoReadlock    },

    /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
    ** flag if there are any active statements. */
    { "read_uncommitted",         SQLITE_ReadUncommitted },

  };
  int i;
  const struct sPragmaType *p;
  for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){
    if( sqlite3StrICmp(zLeft, p->zName)==0 ){
      sqlite3 *db = pParse->db;
      Vdbe *v;







>







186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    /* The following is VERY experimental */
    { "writable_schema",          SQLITE_WriteSchema|SQLITE_RecoveryMode },
    { "omit_readlock",            SQLITE_NoReadlock    },

    /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
    ** flag if there are any active statements. */
    { "read_uncommitted",         SQLITE_ReadUncommitted },
    { "disable_recursive_triggers", SQLITE_NoRecTriggers },
  };
  int i;
  const struct sPragmaType *p;
  for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){
    if( sqlite3StrICmp(zLeft, p->zName)==0 ){
      sqlite3 *db = pParse->db;
      Vdbe *v;

Changes to src/sqliteInt.h.

907
908
909
910
911
912
913

914
915
916
917
918
919
920
#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
#define SQLITE_FullFSync      0x00010000  /* Use full fsync on the backend */
#define SQLITE_LoadExtension  0x00020000  /* Enable load_extension */

#define SQLITE_RecoveryMode   0x00040000  /* Ignore schema errors */
#define SQLITE_ReverseOrder   0x00100000  /* Reverse unordered SELECTs */


/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
*/
#define SQLITE_MAGIC_OPEN     0xa029a697  /* Database is open */







>







907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
#define SQLITE_FullFSync      0x00010000  /* Use full fsync on the backend */
#define SQLITE_LoadExtension  0x00020000  /* Enable load_extension */

#define SQLITE_RecoveryMode   0x00040000  /* Ignore schema errors */
#define SQLITE_ReverseOrder   0x00100000  /* Reverse unordered SELECTs */
#define SQLITE_NoRecTriggers  0x00200000  /* Disable recursive triggers */

/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
*/
#define SQLITE_MAGIC_OPEN     0xa029a697  /* Database is open */

Changes to src/trigger.c.

693
694
695
696
697
698
699




700
701
702
703
704
705
706
...
730
731
732
733
734
735
736



737
738
739
740
741
742
743
...
814
815
816
817
818
819
820
821

822
823
824
825
826
827





828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845


846
847
848
849
850
851
852
...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
    **     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
    **   END;
    **
    **   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
    **   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
    */
    pParse->orconf = (orconfin==OE_Default)?pStep->orconf:orconfin;





    switch( pStep->op ){
      case TK_UPDATE: {
        sqlite3Update(pParse, 
          targetSrcList(pParse, pStep),
          sqlite3ExprListDup(db, pStep->pExprList, 0), 
          sqlite3ExprDup(db, pStep->pWhere, 0), 
................................................................................
        Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0);
        sqlite3SelectDestInit(&sDest, SRT_Discard, 0);
        sqlite3Select(pParse, pSelect, &sDest);
        sqlite3SelectDelete(db, pSelect);
        break;
      }
    } 



    pStep = pStep->pNext;
  }
/* sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); */

  return 0;
}

................................................................................
  pSubParse->pRoot = pRoot;

  /* Push an entry on to the auth context stack */
  sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);

  v = sqlite3GetVdbe(pSubParse);
  if( v ){
    VdbeComment((v, "Trigger: %s (%s %s%s%s ON %s) (%s)", pTrigger->zName,

      (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
        (op==TK_UPDATE ? "UPDATE" : ""),
        (op==TK_INSERT ? "INSERT" : ""),
        (op==TK_DELETE ? "DELETE" : ""),
      pTab->zName, onErrorText(orconf)
    ));






    if( pTrigger->pWhen ){
      /* Code the WHEN clause. If it evaluates to false (or NULL) the 
      ** sub-vdbe is immediately halted.  */
      pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
      if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){
        iEndTrigger = sqlite3VdbeMakeLabel(v);
        sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
      }
      sqlite3ExprDelete(db, pWhen);
    }

    /* Code the trigger program into the sub-vdbe. */
    codeTriggerProgram(pSubParse, pTrigger->step_list, OE_Default);
    if( iEndTrigger ){
      sqlite3VdbeResolveLabel(v, iEndTrigger);
    }
    sqlite3VdbeAddOp0(v, OP_Halt);


    transferParseError(pParse, pSubParse);
    pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg);
    pProgram->nMem = pSubParse->nMem;
    pProgram->nCsr = pSubParse->nTab;
    pProgram->token = (void *)pTrigger;
    pC->oldmask = pSubParse->oldmask;
    pC->newmask = pSubParse->newmask;
................................................................................
      CodedTrigger *pC;
      pC = getRowTrigger(pParse, p, op, pTab, orconf);
      assert( pC || pParse->nErr || pParse->db->mallocFailed );

      /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program 
      ** is a pointer to the sub-vdbe containing the trigger program.  */
      if( pC ){
        sqlite3VdbeAddOp3(v, OP_Program, oldIdx, newIdx, ++pParse->nMem);
        pC->pProgram->nRef++;
        sqlite3VdbeChangeP4(v, -1, (const char *)pC->pProgram, P4_SUBPROGRAM);
        VdbeComment((v, "Call trigger: %s (%s)", p->zName,onErrorText(orconf)));
      }
    }
  }
}

void sqlite3TriggerUses(
  Parse *pParse,       /* Parse context */







>
>
>
>







 







>
>
>







 







|
>




|

>
>
>
>
>













|




>
>







 







|


|







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
...
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
...
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
    **     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
    **   END;
    **
    **   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
    **   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
    */
    pParse->orconf = (orconfin==OE_Default)?pStep->orconf:orconfin;

    if( pStep->op!=TK_SELECT ){
      sqlite3VdbeAddOp1(v, OP_ResetCount, 0);
    }

    switch( pStep->op ){
      case TK_UPDATE: {
        sqlite3Update(pParse, 
          targetSrcList(pParse, pStep),
          sqlite3ExprListDup(db, pStep->pExprList, 0), 
          sqlite3ExprDup(db, pStep->pWhere, 0), 
................................................................................
        Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0);
        sqlite3SelectDestInit(&sDest, SRT_Discard, 0);
        sqlite3Select(pParse, pSelect, &sDest);
        sqlite3SelectDelete(db, pSelect);
        break;
      }
    } 
    if( pStep->op!=TK_SELECT ){
      sqlite3VdbeAddOp1(v, OP_ResetCount, 1);
    }
    pStep = pStep->pNext;
  }
/* sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); */

  return 0;
}

................................................................................
  pSubParse->pRoot = pRoot;

  /* Push an entry on to the auth context stack */
  sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);

  v = sqlite3GetVdbe(pSubParse);
  if( v ){
    VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", 
      pTrigger->zName, onErrorText(orconf),
      (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
        (op==TK_UPDATE ? "UPDATE" : ""),
        (op==TK_INSERT ? "INSERT" : ""),
        (op==TK_DELETE ? "DELETE" : ""),
      pTab->zName
    ));
#ifndef SQLITE_OMIT_TRACE
    sqlite3VdbeChangeP4(v, -1, 
      sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
    );
#endif

    if( pTrigger->pWhen ){
      /* Code the WHEN clause. If it evaluates to false (or NULL) the 
      ** sub-vdbe is immediately halted.  */
      pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
      if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){
        iEndTrigger = sqlite3VdbeMakeLabel(v);
        sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
      }
      sqlite3ExprDelete(db, pWhen);
    }

    /* Code the trigger program into the sub-vdbe. */
    codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
    if( iEndTrigger ){
      sqlite3VdbeResolveLabel(v, iEndTrigger);
    }
    sqlite3VdbeAddOp0(v, OP_Halt);
    VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));

    transferParseError(pParse, pSubParse);
    pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg);
    pProgram->nMem = pSubParse->nMem;
    pProgram->nCsr = pSubParse->nTab;
    pProgram->token = (void *)pTrigger;
    pC->oldmask = pSubParse->oldmask;
    pC->newmask = pSubParse->newmask;
................................................................................
      CodedTrigger *pC;
      pC = getRowTrigger(pParse, p, op, pTab, orconf);
      assert( pC || pParse->nErr || pParse->db->mallocFailed );

      /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program 
      ** is a pointer to the sub-vdbe containing the trigger program.  */
      if( pC ){
        sqlite3VdbeAddOp3(v, OP_Program, oldIdx, ignoreJump, ++pParse->nMem);
        pC->pProgram->nRef++;
        sqlite3VdbeChangeP4(v, -1, (const char *)pC->pProgram, P4_SUBPROGRAM);
        VdbeComment((v, "Call: %s.%s", p->zName, onErrorText(orconf)));
      }
    }
  }
}

void sqlite3TriggerUses(
  Parse *pParse,       /* Parse context */

Changes to src/update.c.

126
127
128
129
130
131
132

133
134
135
136
137
138
139
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
...
278
279
280
281
282
283
284

285
286
287
288
289
290
291
...
416
417
418
419
420
421
422













423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446













447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  /* Register Allocations */
  int regRowCount = 0;   /* A count of rows changed */
  int regOldRowid;       /* The old rowid */
  int regNewRowid;       /* The new rowid */
  int regNew;
  int regOld;
  int regRowSet = 0;     /* Rowset of rows to be updated */


  memset(&sContext, 0, sizeof(sContext));
  db = pParse->db;
  if( pParse->nErr || db->mallocFailed ){
    goto update_cleanup;
  }
  assert( pTabList->nSrc==1 );
................................................................................
  /* Locate the table which we want to update. 
  */
  pTab = sqlite3SrcListLookup(pParse, pTabList);
  if( pTab==0 ) goto update_cleanup;
  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);

  /* Figure out if we have any triggers and if the table being
  ** updated is a view
  */
#ifndef SQLITE_OMIT_TRIGGER
  pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, 0);
  isView = pTab->pSelect!=0;
#else
# define pTrigger 0
# define isView 0
................................................................................
    pParse->nMem += pTab->nCol;
  }
  if( chngRowid || pTrigger ){
    regNewRowid = ++pParse->nMem;
  }
  regNew = pParse->nMem + 1;
  pParse->nMem += pTab->nCol;


  /* Start the view context. */
  if( isView ){
    sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
  }

  /* If there are any triggers, set old_col_mask and new_col_mask. */
................................................................................
        sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew+i);
        sqlite3ColumnDefault(v, pTab, i, regNew+i);
      }else{
        sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
      }
    }
  }














  /* Fire any BEFORE UPDATE triggers. This happens before constraints are
  ** verified. One could argue that this is wrong.  */
  sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
      TRIGGER_BEFORE, pTab, regNew, regOld, onError, addr);

  if( !isView ){

    /* Do constraint checks. */
    sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
        aRegIdx, chngRowid, 1, onError, addr, 0);

    /* Delete the index entries associated with the current record.  */
    j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
  
    /* If changing the record number, delete the old record.  */
    if( chngRowid ){
      sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
    }
    sqlite3VdbeJumpHere(v, j1);
  
    /* Create the new index entries and the new record.  */
    sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx,1,-1,0,0);













  }

  /* Increment the row counter 
  */
  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){
    sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
  }

  sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
      TRIGGER_AFTER, pTab, regNew, regOld, onError, addr);

  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
  sqlite3VdbeJumpHere(v, addr);








>







 







|







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>




|





|











|
|
>
>
>
>
>
>
>
>
>
>
>
>
>









|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  /* Register Allocations */
  int regRowCount = 0;   /* A count of rows changed */
  int regOldRowid;       /* The old rowid */
  int regNewRowid;       /* The new rowid */
  int regNew;
  int regOld;
  int regRowSet = 0;     /* Rowset of rows to be updated */
  int regRec;            /* Register used for new table record to insert */

  memset(&sContext, 0, sizeof(sContext));
  db = pParse->db;
  if( pParse->nErr || db->mallocFailed ){
    goto update_cleanup;
  }
  assert( pTabList->nSrc==1 );
................................................................................
  /* Locate the table which we want to update. 
  */
  pTab = sqlite3SrcListLookup(pParse, pTabList);
  if( pTab==0 ) goto update_cleanup;
  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);

  /* Figure out if we have any triggers and if the table being
  ** updated is a view.
  */
#ifndef SQLITE_OMIT_TRIGGER
  pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, 0);
  isView = pTab->pSelect!=0;
#else
# define pTrigger 0
# define isView 0
................................................................................
    pParse->nMem += pTab->nCol;
  }
  if( chngRowid || pTrigger ){
    regNewRowid = ++pParse->nMem;
  }
  regNew = pParse->nMem + 1;
  pParse->nMem += pTab->nCol;
  regRec = ++pParse->nMem;

  /* Start the view context. */
  if( isView ){
    sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
  }

  /* If there are any triggers, set old_col_mask and new_col_mask. */
................................................................................
        sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew+i);
        sqlite3ColumnDefault(v, pTab, i, regNew+i);
      }else{
        sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
      }
    }
  }

  /* If this is not a view, create the record that will be inserted into
  ** the table (assuming no constraint checks fail). A side effect of
  ** creating the record is applying affinity transformations to the
  ** array of registers populated by the block above. This needs to be
  ** done before the BEFORE triggers are fired.  */
#if 0
  if( !isView ){
    sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, pTab->nCol, regRec);
    sqlite3TableAffinityStr(v, pTab);
    sqlite3ExprCacheAffinityChange(pParse, regNew, pTab->nCol);
  }
#endif

  /* Fire any BEFORE UPDATE triggers. This happens before constraints are
  ** verified. One could argue that this is wrong.  */
  sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
      TRIGGER_BEFORE, pTab, -1, regOldRowid, onError, addr);

  if( !isView ){

    /* Do constraint checks. */
    sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
        aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);

    /* Delete the index entries associated with the current record.  */
    j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
  
    /* If changing the record number, delete the old record.  */
    if( chngRowid ){
      sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
    }
    sqlite3VdbeJumpHere(v, j1);
  
    /* Insert the new index entries and the new record. */
    sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, -1, 0, 0);

#if 0
    for(i=0; i<nIdx; i++){
      if( aRegIdx[i] ){
        sqlite3VdbeAddOp2(v, OP_IdxInsert, iCur+1+i, aRegIdx[i]);
      }
    }
    sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, regNewRowid);
    if( !pParse->nested ){
      sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
      sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_ISUPDATE);
    }
#endif
  }

  /* Increment the row counter 
  */
  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){
    sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
  }

  sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
      TRIGGER_AFTER, pTab, -1, regOldRowid, onError, addr);

  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
  sqlite3VdbeJumpHere(v, addr);

Changes to src/vdbe.c.

848
849
850
851
852
853
854

855
856
857
858
859
860
861
....
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561

3562
3563
3564
3565
3566
3567
3568
....
3613
3614
3615
3616
3617
3618
3619
3620



3621




3622
3623
3624
3625
3626
3627
3628
3629
....
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789

4790




4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804

4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
....
4870
4871
4872
4873
4874
4875
4876


4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890

4891

4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908

4909
4910
4911
4912
4913
4914
4915
4916
4917


4918
4919
4920
4921
4922
4923
4924








4925
4926
4927
4928
4929
4930
4931
case OP_Halt: {
  if( pOp->p1==SQLITE_OK && p->pFrame ){
    VdbeFrame *pFrame = p->pFrame;
    p->pFrame = pFrame->pParent;
    p->nFrame--;
    pc = sqlite3VdbeFrameRestore(pFrame);
    if( pOp->p2==OE_Ignore ){

    }
    break;
  }
  p->rc = pOp->p1;
  p->errorAction = (u8)pOp->p2;
  p->pc = pc;
  if( pOp->p4.z ){
................................................................................
/* 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 written
** written to register P2.
**
** If P3>0 then P3 is a register 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 P3 register is updated with the generated
** record number.  This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
case OP_NewRowid: {           /* out2-prerelease */
  i64 v;                 /* The new rowid */
  VdbeCursor *pC;        /* Cursor of table to get the new rowid */
  int res;               /* Result of an sqlite3BtreeLast() */
  int cnt;               /* Counter to limit the number of searches */
  Mem *pMem;             /* Register holding largest rowid for AUTOINCREMENT */


  v = 0;
  res = 0;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  if( NEVER(pC->pCursor==0) ){
................................................................................
            v++;
          }
        }
      }

#ifndef SQLITE_OMIT_AUTOINCREMENT
      if( pOp->p3 ){
        assert( pOp->p3>0 && pOp->p3<=p->nMem ); /* P3 is a valid memory cell */



        pMem = &p->aMem[pOp->p3];




	REGISTER_TRACE(pOp->p3, pMem);
        sqlite3VdbeMemIntegerify(pMem);
        assert( (pMem->flags & MEM_Int)!=0 );  /* mem(P3) holds an integer */
        if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
          rc = SQLITE_FULL;
          goto abort_due_to_error;
        }
        if( v<pMem->u.i+1 ){
................................................................................
    sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
  }
  break;
}


#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: ContextPush * * * 
**
** Save the current Vdbe context such that it can be restored by a ContextPop
** opcode. The context stores the last insert row id, the last statement change
** count, and the current statement change count.
*/
case OP_ContextPush: {
  int i;
  Context *pContext;

  i = p->contextStackTop++;
  assert( i>=0 );
  /* FIX ME: This should be allocated as part of the vdbe at compile-time */
  if( i>=p->contextStackDepth ){
    p->contextStackDepth = i+1;
    p->contextStack = sqlite3DbReallocOrFree(db, p->contextStack,
                                          sizeof(Context)*(i+1));
    if( p->contextStack==0 ) goto no_mem;
  }
  pContext = &p->contextStack[i];
  pContext->lastRowid = db->lastRowid;
  pContext->nChange = p->nChange;
  break;
}

/* Opcode: ContextPop * * * 
**
** Restore the Vdbe context to the state it was in when contextPush was last
** executed. The context stores the last insert row id, the last statement
** change count, and the current statement change count.
*/
case OP_ContextPop: {
  Context *pContext;
  pContext = &p->contextStack[--p->contextStackTop];
  assert( p->contextStackTop>=0 );
  db->lastRowid = pContext->lastRowid;
  p->nChange = pContext->nChange;
  break;
}

/* Opcode: Program P1 P2 P3 P4 *
**
** Execute a trigger program. P1 contains the address of the memory cell
** that contains the left-most column of the old.* table (unless the trigger
** program is firing as a result of an INSERT statement). P2 is the address 
** of the corresponding column in the new.* table (unless the trigger 
** program is being fired due to a DELETE).

**




** Register P3 contains the address of a memory cell in this (the parent)
** VM that is used to allocate the memory required by the sub-vdbe at 
** runtime.
**
** P4 is a pointer to the VM containing the trigger program.
*/
case OP_Program: {
  VdbeFrame *pFrame;
  SubProgram *pProgram = pOp->p4.pProgram;
  Mem *pRt = &p->aMem[pOp->p3];        /* Register to allocate runtime space */
  assert( pProgram->nOp>0 );
  
  /* If noRecTrigger is true, then recursive invocation of triggers is
  ** disabled for backwards compatibility. 

  ** 
  ** It is recursive invocation of triggers, at the SQL level, that is 
  ** disabled. In some cases a single trigger may generate more than one 
  ** SubProgram (if the trigger may be executed with more than one different 
  ** ON CONFLICT algorithm). SubProgram structures associated with a
  ** single trigger all have the same value for the SubProgram.token 
  ** variable.
  */
  if( 1 || p->noRecTrigger ){
    void *t = pProgram->token;
    for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent);
    if( pFrame ) break;
  }

  /* TODO: This constant should be configurable. */
  if( p->nFrame>1000 ){
................................................................................
    assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
    assert( pProgram->nCsr==pFrame->nChildCsr );
    assert( pc==pFrame->pc );
  }

  p->nFrame++;
  pFrame->pParent = p->pFrame;


  p->pFrame = pFrame;
  p->aMem = &VdbeFrameMem(pFrame)[-1];
  p->nMem = pFrame->nChildMem;
  p->nCursor = pFrame->nChildCsr;
  p->apCsr = (VdbeCursor **)&p->aMem[p->nMem+1];
  p->aOp = pProgram->aOp;
  p->nOp = pProgram->nOp;
  pc = -1;

  break;
}

/* Opcode: TriggerVal P1 P2 P3 * *
**

** Copy a value currently stored in a memory cell of the parent VM to

** a cell in this VMs address space. This is used by trigger programs
** to access the new.* and old.* values.
**
** If parameter P3 is non-zero, then the value read is from the new.*
** table. If P3 is zero, then the value is read from the old.* table.
** Parameter P1 is the index of the required new.* or old.* column (or
** -1 for rowid). 
**
** Parameter P2 is the index of the memory cell in this VM to copy the 
** value to.
*/
case OP_TriggerVal: {           /* out2-prerelease */
  VdbeFrame *pF = p->pFrame;
  Mem *pIn;
  int iFrom = pOp->p1;           /* Memory cell in parent frame */
  iFrom += (pOp->p3 ? pF->aOp[pF->pc].p2 : pF->aOp[pF->pc].p1);
  pIn = &pF->aMem[iFrom];

  sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
  break;
}

#endif /* #ifndef SQLITE_OMIT_TRIGGER */

#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Opcode: MemMax P1 P2 * * *
**


** Set the value of register P1 to the maximum of its current value
** and the value in register P2.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: {        /* in1, in2 */








  sqlite3VdbeMemIntegerify(pIn1);
  sqlite3VdbeMemIntegerify(pIn2);
  if( pIn1->u.i<pIn2->u.i){
    pIn1->u.i = pIn2->u.i;
  }
  break;
}







>







 







|
|
|
|
|








>







 







|
>
>
>
|
>
>
>
>
|







 







<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


<
<
<
<
<
>

>
>
>
>
|
|
<



|





|
|
>








|







 







>
>












|

>
|
>
|
|

<
<
|
|
|
<
<

|
|
<
<
<
<
>









>
>
|
|




|
>
>
>
>
>
>
>
>







848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
....
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
....
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
....
4745
4746
4747
4748
4749
4750
4751









4752






























4753
4754





4755
4756
4757
4758
4759
4760
4761
4762

4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
....
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868


4869
4870
4871


4872
4873
4874




4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
case OP_Halt: {
  if( pOp->p1==SQLITE_OK && p->pFrame ){
    VdbeFrame *pFrame = p->pFrame;
    p->pFrame = pFrame->pParent;
    p->nFrame--;
    pc = sqlite3VdbeFrameRestore(pFrame);
    if( pOp->p2==OE_Ignore ){
      pc = p->aOp[pc].p2-1;
    }
    break;
  }
  p->rc = pOp->p1;
  p->errorAction = (u8)pOp->p2;
  p->pc = pc;
  if( pOp->p4.z ){
................................................................................
/* 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 written
** written to register P2.
**
** If P3>0 then P3 is a register in the root frame of this VDBE 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 P3 register is updated with the '
** generated record number. This P3 mechanism is used to help implement the
** AUTOINCREMENT feature.
*/
case OP_NewRowid: {           /* out2-prerelease */
  i64 v;                 /* The new rowid */
  VdbeCursor *pC;        /* Cursor of table to get the new rowid */
  int res;               /* Result of an sqlite3BtreeLast() */
  int cnt;               /* Counter to limit the number of searches */
  Mem *pMem;             /* Register holding largest rowid for AUTOINCREMENT */
  VdbeFrame *pFrame;     /* Root frame of VDBE */

  v = 0;
  res = 0;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  if( NEVER(pC->pCursor==0) ){
................................................................................
            v++;
          }
        }
      }

#ifndef SQLITE_OMIT_AUTOINCREMENT
      if( pOp->p3 ){
        if( p->pFrame ){
          for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
          pMem = &pFrame->aMem[pOp->p3];
        }else{
          pMem = &p->aMem[pOp->p3];
        }
        /* Assert that P3 is a valid memory cell. */
        assert( pOp->p3>0 && pOp->p3<=(p->pFrame ? pFrame->nMem : p->nMem) );

        REGISTER_TRACE(pOp->p3, pMem);
        sqlite3VdbeMemIntegerify(pMem);
        assert( (pMem->flags & MEM_Int)!=0 );  /* mem(P3) holds an integer */
        if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
          rc = SQLITE_FULL;
          goto abort_due_to_error;
        }
        if( v<pMem->u.i+1 ){
................................................................................
    sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
  }
  break;
}


#ifndef SQLITE_OMIT_TRIGGER








































/* Opcode: Program P1 P2 P3 P4 *
**





** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). 
**
** P1 contains the address of the memory cell that contains the first memory 
** cell in an array of values used as arguments to the sub-program. P2 
** contains the address to jump to if the sub-program throws an IGNORE 
** exception using the RAISE() function. Register P3 contains the address 
** of a memory cell in this (the parent) VM that is used to allocate the 
** memory required by the sub-vdbe at runtime.

**
** P4 is a pointer to the VM containing the trigger program.
*/
case OP_Program: {        /* jump */
  VdbeFrame *pFrame;
  SubProgram *pProgram = pOp->p4.pProgram;
  Mem *pRt = &p->aMem[pOp->p3];        /* Register to allocate runtime space */
  assert( pProgram->nOp>0 );
  
  /* If the SQLITE_NoRecTriggers flag it set, then recursive invocation of
  ** triggers is disabled for backwards compatibility (flag set/cleared by
  ** the "PRAGMA disable_recursive_triggers" command). 
  ** 
  ** It is recursive invocation of triggers, at the SQL level, that is 
  ** disabled. In some cases a single trigger may generate more than one 
  ** SubProgram (if the trigger may be executed with more than one different 
  ** ON CONFLICT algorithm). SubProgram structures associated with a
  ** single trigger all have the same value for the SubProgram.token 
  ** variable.
  */
  if( db->flags&SQLITE_NoRecTriggers ){
    void *t = pProgram->token;
    for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent);
    if( pFrame ) break;
  }

  /* TODO: This constant should be configurable. */
  if( p->nFrame>1000 ){
................................................................................
    assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
    assert( pProgram->nCsr==pFrame->nChildCsr );
    assert( pc==pFrame->pc );
  }

  p->nFrame++;
  pFrame->pParent = p->pFrame;
  pFrame->lastRowid = db->lastRowid;
  pFrame->nChange = p->nChange;
  p->pFrame = pFrame;
  p->aMem = &VdbeFrameMem(pFrame)[-1];
  p->nMem = pFrame->nChildMem;
  p->nCursor = pFrame->nChildCsr;
  p->apCsr = (VdbeCursor **)&p->aMem[p->nMem+1];
  p->aOp = pProgram->aOp;
  p->nOp = pProgram->nOp;
  pc = -1;

  break;
}

/* Opcode: Param P1 P2 * * *
**
** This opcode is only ever present in sub-programs called via the 
** OP_Program instruction. Copy a value currently stored in a memory 
** cell of the calling (parent) frame to cell P2 in the current frames 
** address space. This is used by trigger programs to access the new.* 
** and old.* values.
**


** The address of the cell in the parent frame is determined by adding
** the value of the P1 argument to the value of the P1 argument to the
** calling OP_Program instruction.


*/
case OP_Param: {           /* out2-prerelease */
  VdbeFrame *pFrame = p->pFrame;




  Mem *pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];   
  sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
  break;
}

#endif /* #ifndef SQLITE_OMIT_TRIGGER */

#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Opcode: MemMax P1 P2 * * *
**
** P1 is a register in the root frame of this VM (the root frame is
** different from the current frame if this instruction is being executed
** within a sub-program). Set the value of register P1 to the maximum of 
** its current value and the value in register P2.
**
** This instruction throws an error if the memory cell is not initially
** an integer.
*/
case OP_MemMax: {        /* in2 */
  Mem *pIn1;
  VdbeFrame *pFrame;
  if( p->pFrame ){
    for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
    pIn1 = &pFrame->aMem[pOp->p1];
  }else{
    pIn1 = &p->aMem[pOp->p1];
  }
  sqlite3VdbeMemIntegerify(pIn1);
  sqlite3VdbeMemIntegerify(pIn2);
  if( pIn1->u.i<pIn2->u.i){
    pIn1->u.i = pIn2->u.i;
  }
  break;
}

Changes to src/vdbeInt.h.

99
100
101
102
103
104
105


106
107
108
109
110
111
112
...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  int nMem;               /* Number of entries in aMem */
  VdbeCursor **apCsr;     /* Element of Vdbe cursors */
  u16 nCursor;            /* Number of entries in apCsr */
  VdbeFrame *pParent;     /* Parent of this frame */
  void *token;            /* Copy of SubProgram.token */
  int nChildMem;          /* Number of memory cells for child frame */
  int nChildCsr;          /* Number of cursors for child frame */


};

#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])

/*
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
*/
................................................................................
*/
typedef struct Set Set;
struct Set {
  Hash hash;             /* A set is just a hash table */
  HashElem *prev;        /* Previously accessed hash elemen */
};

/*
** A Context stores the last insert rowid, the last statement change count,
** and the current statement change count (i.e. changes since last statement).
** The current keylist is also stored in the context.
** Elements of Context structure type make up the ContextStack, which is
** updated by the ContextPush and ContextPop opcodes (used by triggers).
** The context is pushed before executing a trigger a popped when the
** trigger finishes.
*/
typedef struct Context Context;
struct Context {
  i64 lastRowid;    /* Last insert rowid (sqlite3.lastRowid) */
  int nChange;      /* Statement changes (Vdbe.nChanges)     */
};

/*
** An instance of the virtual machine.  This structure contains the complete
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
** is really a pointer to an instance of this structure.
**
................................................................................
  u16 nVar;               /* Number of entries in aVar[] */
  Mem *aVar;              /* Values for the OP_Variable opcode. */
  char **azVar;           /* Name of variables */
  u32 magic;              /* Magic number for sanity checking */
  int nMem;               /* Number of memory locations currently allocated */
  Mem *aMem;              /* The memory locations */
  int cacheCtr;           /* VdbeCursor row cache generation counter */
  int contextStackTop;    /* Index of top element in the context stack */
  int contextStackDepth;  /* The size of the "context" stack */
  Context *contextStack;  /* Stack used by opcodes ContextPush & ContextPop*/
  int pc;                 /* The program counter */
  int rc;                 /* Value to return */
  char *zErrMsg;          /* Error message written here */
  u8 explain;             /* True if EXPLAIN present on SQL command */
  u8 changeCntOn;         /* True to update the change-counter */
  u8 expired;             /* True if the VM needs to be recompiled */
  u8 minWriteFileFormat;  /* Minimum file format for writable database files */







>
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
...
241
242
243
244
245
246
247















248
249
250
251
252
253
254
...
280
281
282
283
284
285
286



287
288
289
290
291
292
293
  int nMem;               /* Number of entries in aMem */
  VdbeCursor **apCsr;     /* Element of Vdbe cursors */
  u16 nCursor;            /* Number of entries in apCsr */
  VdbeFrame *pParent;     /* Parent of this frame */
  void *token;            /* Copy of SubProgram.token */
  int nChildMem;          /* Number of memory cells for child frame */
  int nChildCsr;          /* Number of cursors for child frame */
  i64 lastRowid;    /* Last insert rowid (sqlite3.lastRowid) */
  int nChange;      /* Statement changes (Vdbe.nChanges)     */
};

#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])

/*
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
*/
................................................................................
*/
typedef struct Set Set;
struct Set {
  Hash hash;             /* A set is just a hash table */
  HashElem *prev;        /* Previously accessed hash elemen */
};
















/*
** An instance of the virtual machine.  This structure contains the complete
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
** is really a pointer to an instance of this structure.
**
................................................................................
  u16 nVar;               /* Number of entries in aVar[] */
  Mem *aVar;              /* Values for the OP_Variable opcode. */
  char **azVar;           /* Name of variables */
  u32 magic;              /* Magic number for sanity checking */
  int nMem;               /* Number of memory locations currently allocated */
  Mem *aMem;              /* The memory locations */
  int cacheCtr;           /* VdbeCursor row cache generation counter */



  int pc;                 /* The program counter */
  int rc;                 /* Value to return */
  char *zErrMsg;          /* Error message written here */
  u8 explain;             /* True if EXPLAIN present on SQL command */
  u8 changeCntOn;         /* True to update the change-counter */
  u8 expired;             /* True if the VM needs to be recompiled */
  u8 minWriteFileFormat;  /* Minimum file format for writable database files */

Changes to src/vdbeaux.c.

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
....
1332
1333
1334
1335
1336
1337
1338


1339
1340
1341
1342
1343
1344
1345
....
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
      hasStatementBegin = 1;
      p->usesStmtJournal = 1;
    }else if( opcode==OP_Destroy ){
      doesStatementRollback = 1;
    }else if( opcode==OP_Transaction && pOp->p2!=0 ){
      p->readOnly = 0;
#ifndef SQLITE_OMIT_VIRTUALTABLE
    }else if( opcode==OP_VUpdate || opcode==OP_VRename ){
      doesStatementRollback = 1;
    }else if( opcode==OP_VFilter ){
      int n;
      assert( p->nOp - i >= 3 );
      assert( pOp[-1].opcode==OP_Integer );
      n = pOp[-1].p1;
      if( n>nMaxArgs ) nMaxArgs = n;
................................................................................
  Vdbe *v = pFrame->v;
  v->aOp = pFrame->aOp;
  v->nOp = pFrame->nOp;
  v->aMem = pFrame->aMem;
  v->nMem = pFrame->nMem;
  v->apCsr = pFrame->apCsr;
  v->nCursor = pFrame->nCursor;


  return pFrame->pc;
}

/*
** Close all cursors. 
**
** Also release any dynamic memory held by the VM in the Vdbe.aMem memory 
................................................................................
  /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
  ** Vdbe.aMem[] arrays have already been cleaned up.  */
  int i;
  for(i=0; i<p->nCursor; i++){ assert( p->apCsr[i]==0 ); }
  for(i=1; i<=p->nMem; i++){ assert( p->aMem[i].flags==MEM_Null ); }
#endif

  if( p->contextStack ){
    sqlite3DbFree(db, p->contextStack);
  }
  p->contextStack = 0;
  p->contextStackDepth = 0;
  p->contextStackTop = 0;
  sqlite3DbFree(db, p->zErrMsg);
  p->zErrMsg = 0;
  p->pResultSet = 0;
}

/*
** Set the number of result columns that will be returned by this SQL







|







 







>
>







 







<
<
<
<
<
<







291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
....
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
....
1385
1386
1387
1388
1389
1390
1391






1392
1393
1394
1395
1396
1397
1398
      hasStatementBegin = 1;
      p->usesStmtJournal = 1;
    }else if( opcode==OP_Destroy ){
      doesStatementRollback = 1;
    }else if( opcode==OP_Transaction && pOp->p2!=0 ){
      p->readOnly = 0;
#ifndef SQLITE_OMIT_VIRTUALTABLE
    }else if( opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_Program ){
      doesStatementRollback = 1;
    }else if( opcode==OP_VFilter ){
      int n;
      assert( p->nOp - i >= 3 );
      assert( pOp[-1].opcode==OP_Integer );
      n = pOp[-1].p1;
      if( n>nMaxArgs ) nMaxArgs = n;
................................................................................
  Vdbe *v = pFrame->v;
  v->aOp = pFrame->aOp;
  v->nOp = pFrame->nOp;
  v->aMem = pFrame->aMem;
  v->nMem = pFrame->nMem;
  v->apCsr = pFrame->apCsr;
  v->nCursor = pFrame->nCursor;
  v->db->lastRowid = pFrame->lastRowid;
  v->nChange = pFrame->nChange;
  return pFrame->pc;
}

/*
** Close all cursors. 
**
** Also release any dynamic memory held by the VM in the Vdbe.aMem memory 
................................................................................
  /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
  ** Vdbe.aMem[] arrays have already been cleaned up.  */
  int i;
  for(i=0; i<p->nCursor; i++){ assert( p->apCsr[i]==0 ); }
  for(i=1; i<=p->nMem; i++){ assert( p->aMem[i].flags==MEM_Null ); }
#endif







  sqlite3DbFree(db, p->zErrMsg);
  p->zErrMsg = 0;
  p->pResultSet = 0;
}

/*
** Set the number of result columns that will be returned by this SQL

Changes to test/autoinc.test.

553
554
555
556
557
558
559


560
561
562
563
564
565
566
    INSERT INTO t2 VALUES(NULL, 1);
    CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
    INSERT INTO t3 SELECT * FROM t2 WHERE y>1;

    SELECT * FROM sqlite_sequence WHERE name='t3';
  }
} {t3 0}



# Ticket #3928.  Make sure that triggers to not make extra slots in
# the SQLITE_SEQUENCE table.
#
do_test autoinc-3928.1 {
  db eval {
    CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b);







>
>







553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
    INSERT INTO t2 VALUES(NULL, 1);
    CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
    INSERT INTO t3 SELECT * FROM t2 WHERE y>1;

    SELECT * FROM sqlite_sequence WHERE name='t3';
  }
} {t3 0}

catchsql { pragma disable_recursive_triggers = 1 } 

# Ticket #3928.  Make sure that triggers to not make extra slots in
# the SQLITE_SEQUENCE table.
#
do_test autoinc-3928.1 {
  db eval {
    CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b);

Changes to test/misc2.test.

14
15
16
17
18
19
20





21
22
23
24
25
26
27
...
354
355
356
357
358
359
360

361
362
363
364
365
366
367
# left out of other test files.
#
# $Id: misc2.test,v 1.28 2007/09/12 17:01:45 danielk1977 Exp $

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






ifcapable {trigger} {
# Test for ticket #360
#
do_test misc2-1.1 {
  catchsql {
    CREATE TABLE FOO(bar integer);
    CREATE TRIGGER foo_insert BEFORE INSERT ON foo BEGIN
................................................................................
    execsql {SELECT * FROM t1}
  } {1 2 3 4 5 6 7 8 9 10}
}

db close
file delete -force test.db
sqlite3 db test.db


# Ticket #453.  If the SQL ended with "-", the tokenizer was calling that
# an incomplete token, which caused problem.  The solution was to just call
# it a minus sign.
#
do_test misc2-8.1 {
  catchsql {-}







>
>
>
>
>







 







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# left out of other test files.
#
# $Id: misc2.test,v 1.28 2007/09/12 17:01:45 danielk1977 Exp $

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

# The tests in this file were written before SQLite supported recursive
# trigger invocation, and some tests depend on that to pass. So disable
# recursive triggers for this file.
catchsql { pragma disable_recursive_triggers = 1 } 

ifcapable {trigger} {
# Test for ticket #360
#
do_test misc2-1.1 {
  catchsql {
    CREATE TABLE FOO(bar integer);
    CREATE TRIGGER foo_insert BEFORE INSERT ON foo BEGIN
................................................................................
    execsql {SELECT * FROM t1}
  } {1 2 3 4 5 6 7 8 9 10}
}

db close
file delete -force test.db
sqlite3 db test.db
catchsql { pragma disable_recursive_triggers = 1 } 

# Ticket #453.  If the SQL ended with "-", the tokenizer was calling that
# an incomplete token, which caused problem.  The solution was to just call
# it a minus sign.
#
do_test misc2-8.1 {
  catchsql {-}

Changes to test/tkt3731.test.

13
14
15
16
17
18
19





20
21
22
23
24
25
26

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
  finish_test
  return
}






do_test tkt3731-1.1 {
  execsql {
    CREATE TABLE t1(a PRIMARY KEY, b);
    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
      INSERT INTO t1 VALUES(new.a || '+', new.b || '+');
    END;







>
>
>
>
>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
  finish_test
  return
}

# The tests in this file were written before SQLite supported recursive
# trigger invocation, and some tests depend on that to pass. So disable
# recursive triggers for this file.
catchsql { pragma disable_recursive_triggers = 1 } 

do_test tkt3731-1.1 {
  execsql {
    CREATE TABLE t1(a PRIMARY KEY, b);
    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
      INSERT INTO t1 VALUES(new.a || '+', new.b || '+');
    END;

Changes to test/tkt3992.test.

25
26
27
28
29
30
31

32
33
34
35
36
37
38
39
40


41

42

43
44
45
46
47
48
49
..
68
69
70
71
72
73
74
75
76
77
78
79
80
    CREATE TABLE parameters2(
       mountcnt    INT NOT NULL CHECK (typeof(mountcnt) == 'integer'),
       version     REAL CHECK (typeof(version) == 'real')
    );
    INSERT INTO parameters2(mountcnt, version) VALUES(1, 1.0);
  }
} {}


do_test tkt3992-1.2 {
  execsql {
    UPDATE parameters1 SET mountcnt = mountcnt + 1;
    SELECT * FROM parameters1;
  }
} {2 1.0}

do_test tkt3992-1.3 {


  execsql {

    UPDATE parameters2 SET mountcnt = mountcnt + 1;

    SELECT * FROM parameters2;
  }
} {2 1.0}

do_test tkt3992-2.1 {
  execsql {
    CREATE TABLE t1(a, b);
................................................................................
      SELECT tcl('set res', typeof(new.c));
    END;

    UPDATE t2 SET a = 'I';
  }
  set res
} {real}
explain {
    UPDATE t2 SET a = 'I';
}


finish_test







>









>
>

>

>







 







<
<
<



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
..
73
74
75
76
77
78
79



80
81
82
    CREATE TABLE parameters2(
       mountcnt    INT NOT NULL CHECK (typeof(mountcnt) == 'integer'),
       version     REAL CHECK (typeof(version) == 'real')
    );
    INSERT INTO parameters2(mountcnt, version) VALUES(1, 1.0);
  }
} {}
puts [execsql { SELECT *,typeof(mountcnt),typeof(version) FROM parameters1 }]

do_test tkt3992-1.2 {
  execsql {
    UPDATE parameters1 SET mountcnt = mountcnt + 1;
    SELECT * FROM parameters1;
  }
} {2 1.0}

do_test tkt3992-1.3 {
    explain { UPDATE parameters2 SET mountcnt = mountcnt + 1 }
breakpoint
  execsql {
  pragma vdbe_trace = 1;
    UPDATE parameters2 SET mountcnt = mountcnt + 1;
  pragma vdbe_trace = 0;
    SELECT * FROM parameters2;
  }
} {2 1.0}

do_test tkt3992-2.1 {
  execsql {
    CREATE TABLE t1(a, b);
................................................................................
      SELECT tcl('set res', typeof(new.c));
    END;

    UPDATE t2 SET a = 'I';
  }
  set res
} {real}





finish_test

Changes to test/trigger2.test.

49
50
51
52
53
54
55





56
57
58
59
60
61
62

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
  finish_test
  return
}






# 1.
ifcapable subquery {
  set ii 0
  set tbl_definitions [list \
  	{CREATE TABLE tbl (a, b);}                                      \
  	{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);}                  \







>
>
>
>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
  finish_test
  return
}

# The tests in this file were written before SQLite supported recursive
# trigger invocation, and some tests depend on that to pass. So disable
# recursive triggers for this file.
catchsql { pragma disable_recursive_triggers = 1 } 

# 1.
ifcapable subquery {
  set ii 0
  set tbl_definitions [list \
  	{CREATE TABLE tbl (a, b);}                                      \
  	{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);}                  \

Changes to test/trigger3.test.

13
14
15
16
17
18
19
20





21
22
23
24

25
26
27
28
29
30
31
..
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
  finish_test
  return
}






# Test that we can cause ROLLBACK, FAIL and ABORT correctly
# catchsql { DROP TABLE tbl; }
catchsql { CREATE TABLE tbl (a, b, c) }


execsql {
    CREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE 
	WHEN (new.a = 4) THEN RAISE(IGNORE) END;
    END;

    CREATE TRIGGER after_tbl_insert AFTER INSERT ON tbl BEGIN SELECT CASE 
	WHEN (new.a = 1) THEN RAISE(ABORT,    'Trigger abort') 
................................................................................
do_test trigger3-1.3 {
    execsql {SELECT * FROM tbl}
} {}

# FAIL
do_test trigger3-2.1 {
    catchsql {
	BEGIN;
        INSERT INTO tbl VALUES (5, 5, 6);
        INSERT INTO tbl VALUES (2, 5, 6);
    }
} {1 {Trigger fail}}
do_test trigger3-2.2 {
    execsql {
	SELECT * FROM tbl;








>
>
>
>
>

<
<
|
>







 







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26


27
28
29
30
31
32
33
34
35
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable {!trigger} {
  finish_test
  return
}

# The tests in this file were written before SQLite supported recursive }
# trigger invocation, and some tests depend on that to pass. So disable
# recursive triggers for this file.
catchsql { pragma disable_recursive_triggers = 1 } 

# Test that we can cause ROLLBACK, FAIL and ABORT correctly


#
catchsql { CREATE TABLE tbl(a, b ,c) }
execsql {
    CREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE 
	WHEN (new.a = 4) THEN RAISE(IGNORE) END;
    END;

    CREATE TRIGGER after_tbl_insert AFTER INSERT ON tbl BEGIN SELECT CASE 
	WHEN (new.a = 1) THEN RAISE(ABORT,    'Trigger abort') 
................................................................................
do_test trigger3-1.3 {
    execsql {SELECT * FROM tbl}
} {}

# FAIL
do_test trigger3-2.1 {
    catchsql {
        BEGIN;
        INSERT INTO tbl VALUES (5, 5, 6);
        INSERT INTO tbl VALUES (2, 5, 6);
    }
} {1 {Trigger fail}}
do_test trigger3-2.2 {
    execsql {
	SELECT * FROM tbl;

Changes to test/trigger9.test.

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
..
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
      END;
      DELETE FROM t1;
      SELECT * FROM t2;
  }
} {1 2 3}
do_test trigger9-1.3.2 {
  has_rowdata {DELETE FROM t1}
} 1
do_test trigger9-1.3.3 { execsql { ROLLBACK } } {}

do_test trigger9-1.4.1 {
  execsql {
    BEGIN;
      CREATE TRIGGER trig1 BEFORE DELETE ON t1 WHEN old.x='1' BEGIN
        INSERT INTO t2 VALUES(old.rowid);
................................................................................
      END;
      DELETE FROM t1;
      SELECT * FROM t2;
  }
} {1}
do_test trigger9-1.4.2 {
  has_rowdata {DELETE FROM t1}
} 1
do_test trigger9-1.4.3 { execsql { ROLLBACK } } {}

do_test trigger9-1.5.1 {
  execsql {
    BEGIN;
      CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN
        INSERT INTO t2 VALUES(old.rowid);
................................................................................
      END;
      UPDATE t1 SET y = '';
      SELECT * FROM t2;
  }
} {1 2 3}
do_test trigger9-1.6.2 {
  has_rowdata {UPDATE t1 SET y = ''}
} 1
do_test trigger9-1.6.3 { execsql { ROLLBACK } } {}

do_test trigger9-1.7.1 {
  execsql {
    BEGIN;
      CREATE TRIGGER trig1 BEFORE UPDATE ON t1 WHEN old.x>='2' BEGIN
        INSERT INTO t2 VALUES(old.x);
................................................................................
      END;
      UPDATE t1 SET y = '';
      SELECT * FROM t2;
  }
} {2 3}
do_test trigger9-1.7.2 {
  has_rowdata {UPDATE t1 SET y = ''}
} 1
do_test trigger9-1.7.3 { execsql { ROLLBACK } } {}

do_test trigger9-3.1 {
  execsql {
    CREATE TABLE t3(a, b);
    INSERT INTO t3 VALUES(1, 'one');
    INSERT INTO t3 VALUES(2, 'two');







|







 







|







 







|







 







|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
..
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
      END;
      DELETE FROM t1;
      SELECT * FROM t2;
  }
} {1 2 3}
do_test trigger9-1.3.2 {
  has_rowdata {DELETE FROM t1}
} 0
do_test trigger9-1.3.3 { execsql { ROLLBACK } } {}

do_test trigger9-1.4.1 {
  execsql {
    BEGIN;
      CREATE TRIGGER trig1 BEFORE DELETE ON t1 WHEN old.x='1' BEGIN
        INSERT INTO t2 VALUES(old.rowid);
................................................................................
      END;
      DELETE FROM t1;
      SELECT * FROM t2;
  }
} {1}
do_test trigger9-1.4.2 {
  has_rowdata {DELETE FROM t1}
} 0
do_test trigger9-1.4.3 { execsql { ROLLBACK } } {}

do_test trigger9-1.5.1 {
  execsql {
    BEGIN;
      CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN
        INSERT INTO t2 VALUES(old.rowid);
................................................................................
      END;
      UPDATE t1 SET y = '';
      SELECT * FROM t2;
  }
} {1 2 3}
do_test trigger9-1.6.2 {
  has_rowdata {UPDATE t1 SET y = ''}
} 0
do_test trigger9-1.6.3 { execsql { ROLLBACK } } {}

do_test trigger9-1.7.1 {
  execsql {
    BEGIN;
      CREATE TRIGGER trig1 BEFORE UPDATE ON t1 WHEN old.x>='2' BEGIN
        INSERT INTO t2 VALUES(old.x);
................................................................................
      END;
      UPDATE t1 SET y = '';
      SELECT * FROM t2;
  }
} {2 3}
do_test trigger9-1.7.2 {
  has_rowdata {UPDATE t1 SET y = ''}
} 0
do_test trigger9-1.7.3 { execsql { ROLLBACK } } {}

do_test trigger9-3.1 {
  execsql {
    CREATE TABLE t3(a, b);
    INSERT INTO t3 VALUES(1, 'one');
    INSERT INTO t3 VALUES(2, 'two');