SQLite4
Check-in [b480943c48]
Not logged in

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

Overview
Comment:Get most of the trigger logic working again. Still some problems.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | primary-keys
Files: files | file ages | folders
SHA1: b480943c48bbed91efe6b29df6e99818b0e7968a
User & Date: dan 2012-04-16 19:04:57
Context
2012-04-17
05:36
Fix an issue with sub-transaction rollback. check-in: 123a055a36 user: dan tags: primary-keys
2012-04-16
19:04
Get most of the trigger logic working again. Still some problems. check-in: b480943c48 user: dan tags: primary-keys
2012-04-14
19:38
Fixes to foreign key logic. And other things. check-in: 69cf7caf80 user: dan tags: primary-keys
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/delete.c.

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
...
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
...
471
472
473
474
475
476
477
478
479

480
481
482
483
484
485
486
487
488
489
490
491
...
507
508
509
510
511
512
513
514






515
516
517
518
519
520
521



522
523
524
525
526
527
528
...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int iCur;              /* VDBE Cursor number for pTab */
  sqlite4 *db;           /* Main database structure */
  AuthContext sContext;  /* Authorization context */
  NameContext sNC;       /* Name context to resolve expressions in */
  int iDb;               /* Database number */
  int memCnt = -1;       /* Memory cell used for change counting */
  int rcauth;            /* Value returned by authorization callback */

#ifndef SQLITE_OMIT_TRIGGER
  int isView;                  /* True if attempting to delete from a view */
  Trigger *pTrigger;           /* List of table triggers, if required */
#endif

................................................................................
  zDb = db->aDb[iDb].zName;
  rcauth = sqlite4AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
  assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
  if( rcauth==SQLITE_DENY ){
    goto delete_from_cleanup;
  }

  /* Assign  cursor number to the table and all its indices. */
  assert( pTabList->nSrc==1 );
  iCur = pTabList->a[0].iCursor = pParse->nTab++;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }

  /* Start the view context
................................................................................
    VdbeComment((v, "initialize KeySet"));
    pWInfo = sqlite4WhereBegin(
        pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
    );
    if( pWInfo==0 ) goto delete_from_cleanup;
    sqlite4VdbeAddOp2(v, OP_RowKey, iCur, regKey);
    sqlite4VdbeAddOp2(v, OP_KeySetAdd, regSet, regKey);
    if( db->flags & SQLITE_CountRows ){
      sqlite4VdbeAddOp2(v, OP_AddImm, memCnt, 1);
    }
    sqlite4WhereEnd(pWInfo);

    /* Unless this is a view, open cursors for all indexes on the table
    ** from which we are deleting.  */
    if( !isView ){
      sqlite4OpenAllIndexes(pParse, pTab, iCur, OP_OpenWrite);
    }
................................................................................
  ** maximum rowid counter values recorded while inserting into
  ** autoincrement tables.
  */
  if( pParse->nested==0 && pParse->pTriggerTab==0 ){
    sqlite4AutoincrementEnd(pParse);
  }

  /* Return the number of rows that were deleted. If this routine is 
  ** generating code because of a call to sqlite4NestedParse(), do not
  ** invoke the callback function.
  */
  if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
    sqlite4VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
    sqlite4VdbeSetNumCols(v, 1);
    sqlite4VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
  }

delete_from_cleanup:
  sqlite4AuthContextPop(&sContext);
  sqlite4SrcListDelete(db, pTabList);
  sqlite4ExprDelete(db, pWhere);
  return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
................................................................................
  int bCount,                     /* True to increment the row change counter */
  Trigger *pTrigger,              /* List of triggers to (potentially) fire */
  int onconf                      /* Default ON CONFLICT policy for triggers */
){
  Vdbe *v = pParse->pVdbe;        /* Vdbe */
  int regOld = 0;                 /* First register in OLD.* array */
  int iLabel;                     /* Label resolved to end of generated code */
  int iPk;
  int iPkCsr;                     /* Primary key cursor number */


  /* Vdbe is guaranteed to have been allocated by this stage. */
  assert( v );

  sqlite4FindPrimaryKey(pTab, &iPk);
  iPkCsr = baseCur + iPk;

  /* Seek the PK cursor to the row to delete. If this row no longer exists 
  ** (this can happen if a trigger program has already deleted it), do
  ** not attempt to delete it or fire any DELETE triggers.  */
  iLabel = sqlite4VdbeMakeLabel(v);
  sqlite4VdbeAddOp4Int(v, OP_NotFound, iPkCsr, iLabel, regKey, 0);
................................................................................
    mask = sqlite4TriggerColmask(
        pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf
    );
    mask |= sqlite4FkOldmask(pParse, pTab);

    /* Allocate an array of registers - one for each column in the table.
    ** Then populate those array elements that may be used by FK or trigger
    ** logic with the OLD.* values.  */






    regOld = pParse->nMem+1;
    pParse->nMem += pTab->nCol;
    for(iCol=0; iCol<pTab->nCol; iCol++){
      if( mask==0xffffffff || mask&(1<<iCol) ){
        sqlite4ExprCodeGetColumnOfTable(v, pTab, iPkCsr, iCol, regOld+iCol);
      }
    }




    /* Invoke BEFORE DELETE trigger programs. */
    sqlite4CodeRowTrigger(pParse, pTrigger, 
        TK_DELETE, 0, TRIGGER_BEFORE, pTab, regOld, onconf, iLabel
    );

    /* Seek the cursor to the row to be deleted again. It may be that
................................................................................
    ** being deleted. Do not attempt to delete the row a second time, and 
    ** do not fire AFTER triggers.  */
    sqlite4VdbeAddOp4Int(v, OP_NotFound, iPkCsr, iLabel, regKey, 0);

    /* Do FK processing. This call checks that any FK constraints that
    ** refer to this table (i.e. constraints attached to other tables) 
    ** are not violated by deleting this row.  */
    sqlite4FkCheck(pParse, pTab, regOld, 0);
  }

  /* Delete the index and table entries. Skip this step if pTab is really
  ** a view (in which case the only effect of the DELETE statement is to
  ** fire the INSTEAD OF triggers).  */ 
  if( pTab->pSelect==0 ){
    sqlite4GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
................................................................................
#endif
  }

  /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
  ** handle rows (possibly in other tables) that refer via a foreign key
  ** to the row just deleted. This is a no-op if there are no configured
  ** foreign keys that use this table as a parent table.  */ 
  sqlite4FkActions(pParse, pTab, 0, regOld);

  /* Invoke AFTER DELETE trigger programs. */
  sqlite4CodeRowTrigger(pParse, pTrigger, 
      TK_DELETE, 0, TRIGGER_AFTER, pTab, regOld, onconf, iLabel
  );

  /* Jump here if the row had already been deleted before any BEFORE
................................................................................
      );
      sqlite4VdbeAddOp1(v, OP_Delete, baseCur+i);
      sqlite4VdbeJumpHere(v, addrNotFound);
    }
  }

  sqlite4VdbeAddOp1(v, OP_Delete, baseCur+iPk);

  sqlite4ReleaseTempReg(pParse, regKey);
}

/*
** Generate code that will assemble an index key and put it in register
** regOut.  The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to







<







 







|







 







<
<
<







 







<
<
<
<
<
<
<
<
<
<







 







|

>




|







 







|
>
>
>
>
>
>

|


|


>
>
>







 







|







 







|







 







<







232
233
234
235
236
237
238

239
240
241
242
243
244
245
...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
...
367
368
369
370
371
372
373



374
375
376
377
378
379
380
...
410
411
412
413
414
415
416










417
418
419
420
421
422
423
...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
...
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
...
641
642
643
644
645
646
647

648
649
650
651
652
653
654
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int iCur;              /* VDBE Cursor number for pTab */
  sqlite4 *db;           /* Main database structure */
  AuthContext sContext;  /* Authorization context */
  NameContext sNC;       /* Name context to resolve expressions in */
  int iDb;               /* Database number */

  int rcauth;            /* Value returned by authorization callback */

#ifndef SQLITE_OMIT_TRIGGER
  int isView;                  /* True if attempting to delete from a view */
  Trigger *pTrigger;           /* List of table triggers, if required */
#endif

................................................................................
  zDb = db->aDb[iDb].zName;
  rcauth = sqlite4AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
  assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
  if( rcauth==SQLITE_DENY ){
    goto delete_from_cleanup;
  }

  /* Assign cursor numbers to each of the tables indexes. */
  assert( pTabList->nSrc==1 );
  iCur = pTabList->a[0].iCursor = pParse->nTab++;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }

  /* Start the view context
................................................................................
    VdbeComment((v, "initialize KeySet"));
    pWInfo = sqlite4WhereBegin(
        pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK
    );
    if( pWInfo==0 ) goto delete_from_cleanup;
    sqlite4VdbeAddOp2(v, OP_RowKey, iCur, regKey);
    sqlite4VdbeAddOp2(v, OP_KeySetAdd, regSet, regKey);



    sqlite4WhereEnd(pWInfo);

    /* Unless this is a view, open cursors for all indexes on the table
    ** from which we are deleting.  */
    if( !isView ){
      sqlite4OpenAllIndexes(pParse, pTab, iCur, OP_OpenWrite);
    }
................................................................................
  ** maximum rowid counter values recorded while inserting into
  ** autoincrement tables.
  */
  if( pParse->nested==0 && pParse->pTriggerTab==0 ){
    sqlite4AutoincrementEnd(pParse);
  }











delete_from_cleanup:
  sqlite4AuthContextPop(&sContext);
  sqlite4SrcListDelete(db, pTabList);
  sqlite4ExprDelete(db, pWhere);
  return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
................................................................................
  int bCount,                     /* True to increment the row change counter */
  Trigger *pTrigger,              /* List of triggers to (potentially) fire */
  int onconf                      /* Default ON CONFLICT policy for triggers */
){
  Vdbe *v = pParse->pVdbe;        /* Vdbe */
  int regOld = 0;                 /* First register in OLD.* array */
  int iLabel;                     /* Label resolved to end of generated code */
  int iPk;                        /* Offset of PK cursor in cursor array */
  int iPkCsr;                     /* Primary key cursor number */
  Index *pPk;                     /* Primary key index */

  /* Vdbe is guaranteed to have been allocated by this stage. */
  assert( v );

  pPk = sqlite4FindPrimaryKey(pTab, &iPk);
  iPkCsr = baseCur + iPk;

  /* Seek the PK cursor to the row to delete. If this row no longer exists 
  ** (this can happen if a trigger program has already deleted it), do
  ** not attempt to delete it or fire any DELETE triggers.  */
  iLabel = sqlite4VdbeMakeLabel(v);
  sqlite4VdbeAddOp4Int(v, OP_NotFound, iPkCsr, iLabel, regKey, 0);
................................................................................
    mask = sqlite4TriggerColmask(
        pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf
    );
    mask |= sqlite4FkOldmask(pParse, pTab);

    /* Allocate an array of registers - one for each column in the table.
    ** Then populate those array elements that may be used by FK or trigger
    ** logic with the OLD.* values.
    **
    ** The array is (nCol+1) registers in size, where nCol is the number of
    ** columns in the table. If the table has an implicit PK, the first 
    ** register in the array contains the rowid. Otherwise, its contents are
    ** undefined.  
    */
    regOld = pParse->nMem+1;
    pParse->nMem += (pTab->nCol+1);
    for(iCol=0; iCol<pTab->nCol; iCol++){
      if( mask==0xffffffff || mask&(1<<iCol) ){
        sqlite4ExprCodeGetColumnOfTable(v, pTab, iPkCsr, iCol, regOld+iCol+1);
      }
    }
    if( pPk->aiColumn[0]<0 ){
      sqlite4VdbeAddOp2(v, OP_Rowid, iPkCsr, regOld);
    }

    /* Invoke BEFORE DELETE trigger programs. */
    sqlite4CodeRowTrigger(pParse, pTrigger, 
        TK_DELETE, 0, TRIGGER_BEFORE, pTab, regOld, onconf, iLabel
    );

    /* Seek the cursor to the row to be deleted again. It may be that
................................................................................
    ** being deleted. Do not attempt to delete the row a second time, and 
    ** do not fire AFTER triggers.  */
    sqlite4VdbeAddOp4Int(v, OP_NotFound, iPkCsr, iLabel, regKey, 0);

    /* Do FK processing. This call checks that any FK constraints that
    ** refer to this table (i.e. constraints attached to other tables) 
    ** are not violated by deleting this row.  */
    sqlite4FkCheck(pParse, pTab, regOld+1, 0);
  }

  /* Delete the index and table entries. Skip this step if pTab is really
  ** a view (in which case the only effect of the DELETE statement is to
  ** fire the INSTEAD OF triggers).  */ 
  if( pTab->pSelect==0 ){
    sqlite4GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
................................................................................
#endif
  }

  /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
  ** handle rows (possibly in other tables) that refer via a foreign key
  ** to the row just deleted. This is a no-op if there are no configured
  ** foreign keys that use this table as a parent table.  */ 
  sqlite4FkActions(pParse, pTab, 0, regOld+1);

  /* Invoke AFTER DELETE trigger programs. */
  sqlite4CodeRowTrigger(pParse, pTrigger, 
      TK_DELETE, 0, TRIGGER_AFTER, pTab, regOld, onconf, iLabel
  );

  /* Jump here if the row had already been deleted before any BEFORE
................................................................................
      );
      sqlite4VdbeAddOp1(v, OP_Delete, baseCur+i);
      sqlite4VdbeJumpHere(v, addrNotFound);
    }
  }

  sqlite4VdbeAddOp1(v, OP_Delete, baseCur+iPk);

  sqlite4ReleaseTempReg(pParse, regKey);
}

/*
** Generate code that will assemble an index key and put it in register
** regOut.  The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to

Changes to src/expr.c.

2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
....
2723
2724
2725
2726
2727
2728
2729





2730
2731
2732
2733
2734
2735
2736

    case TK_TRIGGER: {
      /* If the opcode is TK_TRIGGER, then the expression is a reference
      ** to a column in the new.* or old.* pseudo-tables available to
      ** trigger programs. In this case Expr.iTable is set to 1 for the
      ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
      ** is set to the column of the pseudo-table to read, or to -1 to
      ** read the rowid field.
      **
      ** The expression is implemented using an OP_Param opcode. The p1
      ** parameter is set to 0 for an old.rowid reference, or to (i+1)
      ** to reference another column of the old.* pseudo-table, where 
      ** i is the index of the column. For a new.rowid reference, p1 is
      ** set to (n+1), where n is the number of columns in each pseudo-table.
      ** For a reference to any other column in the new.* pseudo-table, p1
................................................................................
      **   CREATE TABLE t1(a, b);
      **
      ** Then p1 is interpreted as follows:
      **
      **   p1==0   ->    old.rowid     p1==3   ->    new.rowid
      **   p1==1   ->    old.a         p1==4   ->    new.a
      **   p1==2   ->    old.b         p1==5   ->    new.b       





      */
      Table *pTab = pExpr->pTab;
      int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;

      assert( pExpr->iTable==0 || pExpr->iTable==1 );
      assert( pExpr->iColumn>=-1 && pExpr->iColumn<pTab->nCol );
      assert( p1>=0 && p1<(pTab->nCol*2+2) );







|







 







>
>
>
>
>







2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
....
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741

    case TK_TRIGGER: {
      /* If the opcode is TK_TRIGGER, then the expression is a reference
      ** to a column in the new.* or old.* pseudo-tables available to
      ** trigger programs. In this case Expr.iTable is set to 1 for the
      ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
      ** is set to the column of the pseudo-table to read, or to -1 to
      ** read the rowid field (if applicable - see below).
      **
      ** The expression is implemented using an OP_Param opcode. The p1
      ** parameter is set to 0 for an old.rowid reference, or to (i+1)
      ** to reference another column of the old.* pseudo-table, where 
      ** i is the index of the column. For a new.rowid reference, p1 is
      ** set to (n+1), where n is the number of columns in each pseudo-table.
      ** For a reference to any other column in the new.* pseudo-table, p1
................................................................................
      **   CREATE TABLE t1(a, b);
      **
      ** Then p1 is interpreted as follows:
      **
      **   p1==0   ->    old.rowid     p1==3   ->    new.rowid
      **   p1==1   ->    old.a         p1==4   ->    new.a
      **   p1==2   ->    old.b         p1==5   ->    new.b       
      **
      ** As of SQLite 4, the rowid references are only valid if the table is
      ** declared without an explicit PRIMARY KEY (as it is in the example
      ** above). If the table does have an explicit PRIMARY KEY, the contents
      ** of the old.rowid and new.rowid registers are not defined.
      */
      Table *pTab = pExpr->pTab;
      int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;

      assert( pExpr->iTable==0 || pExpr->iTable==1 );
      assert( pExpr->iColumn>=-1 && pExpr->iColumn<pTab->nCol );
      assert( p1>=0 && p1<(pTab->nCol*2+2) );

Changes to src/insert.c.

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
883
884
885
886
887
888
889
890
891
892
893
894

895
896
897
898

899
900
901
902


903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919




920
921


922
923
924
925
926
927
928
929

930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013

1014
1015
1016
1017
1018
1019
1020
1021
1022
1023


1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039

1040
1041
1042

1043
1044
1045
1046
1047
1048
1049
....
1542
1543
1544
1545
1546
1547
1548

1549
1550
1551
1552
1553
1554
1555
    addrInsTop = sqlite4VdbeAddOp1(v, OP_If, regEof);
  }

  /* Allocate an array of registers in which to assemble the values for the
  ** new row. If the table has an explicit primary key, we need one register
  ** for each table column. If the table uses an implicit primary key, the
  ** nCol+1 registers are required.  */
  if( bImplicitPK ) regRowid = ++pParse->nMem;
  regContent = pParse->nMem+1;
  pParse->nMem += pTab->nCol;

  if( IsVirtual(pTab) ){
    /* TODO: Fix this */
    regContent++;
    regRowid++;
    pParse->nMem++;
  }

  /* Run the BEFORE and INSTEAD OF triggers, if there are any
  */
  endOfLoop = sqlite4VdbeMakeLabel(v);
  if( tmask & TRIGGER_BEFORE ){
    int regCols = sqlite4GetTempRange(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 ){
      sqlite4VdbeAddOp2(v, OP_Integer, -1, regCols);
    }else{
      int j1;
      if( useTempTable ){
        sqlite4VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regCols);
      }else{
        assert( pSelect==0 );  /* Otherwise useTempTable is true */
        sqlite4ExprCode(pParse, pList->a[keyColumn].pExpr, regCols);
      }
      j1 = sqlite4VdbeAddOp1(v, OP_NotNull, regCols);
      sqlite4VdbeAddOp2(v, OP_Integer, -1, regCols);
      sqlite4VdbeJumpHere(v, j1);
      sqlite4VdbeAddOp1(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( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
        sqlite4ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
      }else if( useTempTable ){
        sqlite4VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); 


      }else{
        assert( pSelect==0 ); /* Otherwise useTempTable is true */
        sqlite4ExprCodeAndCache(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 ){
      sqlite4VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol);
      sqlite4TableAffinityStr(v, pTab);
    }

    /* Fire BEFORE or INSTEAD OF triggers */




    sqlite4CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, 
        pTab, regCols-pTab->nCol-1, onError, endOfLoop);



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

  if( !isView ){
    /* If this table has an implicit PRIMARY KEY, populate the regRowid
    ** register with the value to use for the new row.  */
    if( bImplicitPK ){

      sqlite4VdbeAddOp2(v, OP_NewRowid, baseCur+iPk, regRowid);
    }

#if 0
    if( IsVirtual(pTab) ){
      /* The row that the VUpdate opcode will delete: none */
      sqlite4VdbeAddOp2(v, OP_Null, 0, regIns);
    }
    if( keyColumn>=0 ){
      if( useTempTable ){
        sqlite4VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
      }else if( pSelect ){
        sqlite4VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid);
      }else{
        VdbeOp *pOp;
        sqlite4ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
        pOp = sqlite4VdbeGetOp(v, -1);
        if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
          appendFlag = 1;
          pOp->opcode = OP_NewRowid;
          pOp->p1 = baseCur;
          pOp->p2 = regRowid;
          pOp->p3 = regAutoinc;
        }
      }
      /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
      ** to generate a unique primary key value.
      */
      if( !appendFlag ){
        int j1;
        if( !IsVirtual(pTab) ){
          j1 = sqlite4VdbeAddOp1(v, OP_NotNull, regRowid);
          sqlite4VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
          sqlite4VdbeJumpHere(v, j1);
        }else{
          j1 = sqlite4VdbeCurrentAddr(v);
          sqlite4VdbeAddOp2(v, OP_IsNull, regRowid, j1+2);
        }
        sqlite4VdbeAddOp1(v, OP_MustBeInt, regRowid);
      }
    }else if( IsVirtual(pTab) ){
      sqlite4VdbeAddOp2(v, OP_Null, 0, regRowid);
    }else{
      sqlite4VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
      appendFlag = 1;
    }
    autoIncStep(pParse, regAutoinc, regRowid);
#endif

    /* 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 = regContent + i;
      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) ){
        sqlite4ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
      }else if( useTempTable ){
        sqlite4VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); 
      }else if( pSelect ){
        sqlite4VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
      }else{
        sqlite4ExprCode(pParse, pList->a[j].pExpr, iRegStore);
      }
    }

    sqlite4VdbeAddOp2(v, OP_Affinity, regContent, pTab->nCol);
    sqlite4TableAffinityStr(v, pTab);

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */

#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( IsVirtual(pTab) ){
      const char *pVTab = (const char *)sqlite4GetVTable(db, pTab);
      sqlite4VtabMakeWritable(pParse, pTab);
      sqlite4VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
      sqlite4VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
      sqlite4MayAbort(pParse);
    }else
#endif
    {


      int isReplace;    /* Set to true if constraints may cause a replace */

      sqlite4GenerateConstraintChecks(pParse, pTab, baseCur, 
          regContent, aRegIdx, 0, 0, onError, endOfLoop, &isReplace
      );

      sqlite4FkCheck(pParse, pTab, 0, regContent);

      sqlite4CompleteInsertion(pParse, pTab, baseCur, 
          regContent, aRegIdx, 0, appendFlag, isReplace==0
      );
    }
  }

  if( pTrigger ){
    /* Code AFTER triggers */

    sqlite4CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, 
        pTab, regData-2-pTab->nCol, onError, endOfLoop);
  }


  /* The bottom of the main insertion loop, if the data source
  ** is a SELECT statement.
  */
  sqlite4VdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
    sqlite4VdbeAddOp2(v, OP_Next, srcTab, addrCont);
................................................................................
      int regData = 0;
      int flags = 0;
      if( pIdx->eIndexType==SQLITE_INDEX_PRIMARYKEY ){
        regData = regRec;
        flags = pik_flags;
      }
      sqlite4VdbeAddOp3(v, OP_IdxInsert, baseCur+i, regData, aRegIdx[i]);

    }
  }
}

/*
** Generate code that will open cursors for a table and for all
** indices of that table.  The "baseCur" parameter is the cursor number used







|










<
<

<
<

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

<
<
<
<
<
|
|
|
|

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

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>










>
>

<



<

<






<
|
>
|
|
<
>







 







>







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
883
884
885
886
887
888

889
890
891

892




893
894
895
896
897

















































































898
899
900
901
902
903
904
905
906
907
908
909
910
911

912
913
914

915

916
917
918
919
920
921

922
923
924
925

926
927
928
929
930
931
932
933
....
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
    addrInsTop = sqlite4VdbeAddOp1(v, OP_If, regEof);
  }

  /* Allocate an array of registers in which to assemble the values for the
  ** new row. If the table has an explicit primary key, we need one register
  ** for each table column. If the table uses an implicit primary key, the
  ** nCol+1 registers are required.  */
  regRowid = ++pParse->nMem;
  regContent = pParse->nMem+1;
  pParse->nMem += pTab->nCol;

  if( IsVirtual(pTab) ){
    /* TODO: Fix this */
    regContent++;
    regRowid++;
    pParse->nMem++;
  }



  endOfLoop = sqlite4VdbeMakeLabel(v);
































  for(i=0; i<pTab->nCol; i++){

    j = i;

    if( pColumn ){
      for(j=0; j<pColumn->nId; j++){
        if( pColumn->a[j].idx==i ) break;
      }
    }

    if( nColumn==0 || (pColumn && j>=pColumn->nId) ){
      sqlite4ExprCode(pParse, pTab->aCol[i].pDflt, regContent+i);
    }else if( useTempTable ){
      sqlite4VdbeAddOp3(v, OP_Column, srcTab, j, regContent+i);
    }else if( pSelect ){
      sqlite4VdbeAddOp2(v, OP_SCopy, regFromSelect+j, regContent+i);
    }else{
      assert( pSelect==0 ); /* Otherwise useTempTable is true */
      sqlite4ExprCodeAndCache(pParse, pList->a[j].pExpr, regContent+i);
    }
  }






  if( !isView ){
    sqlite4VdbeAddOp2(v, OP_Affinity, regContent, pTab->nCol);
    sqlite4TableAffinityStr(v, pTab);
  }

  /* Fire BEFORE or INSTEAD OF triggers */
  if( pTrigger ){
    sqlite4VdbeAddOp2(v, OP_Integer, -1, regRowid);
    VdbeComment((v, "new.rowid value for BEFORE triggers"));
    sqlite4CodeRowTrigger(
        pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, 

        pTab, (regRowid - pTab->nCol - 1), onError, endOfLoop
    );
  }






  if( bImplicitPK ){
    assert( !isView );
    sqlite4VdbeAddOp2(v, OP_NewRowid, baseCur+iPk, regRowid);
  }


















































































  if( !isView ){
#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( IsVirtual(pTab) ){
      const char *pVTab = (const char *)sqlite4GetVTable(db, pTab);
      sqlite4VtabMakeWritable(pParse, pTab);
      sqlite4VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
      sqlite4VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
      sqlite4MayAbort(pParse);
    }else
#endif
    {
      /* Generate code to check constraints and generate index keys and
      ** do the insertion.  */
      int isReplace;    /* Set to true if constraints may cause a replace */

      sqlite4GenerateConstraintChecks(pParse, pTab, baseCur, 
          regContent, aRegIdx, 0, 0, onError, endOfLoop, &isReplace
      );

      sqlite4FkCheck(pParse, pTab, 0, regContent);

      sqlite4CompleteInsertion(pParse, pTab, baseCur, 
          regContent, aRegIdx, 0, appendFlag, isReplace==0
      );
    }
  }


  /* Code AFTER triggers */
  sqlite4CodeRowTrigger(
      pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, 
      pTab, regRowid - pTab->nCol - 1, onError, endOfLoop

  );

  /* The bottom of the main insertion loop, if the data source
  ** is a SELECT statement.
  */
  sqlite4VdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
    sqlite4VdbeAddOp2(v, OP_Next, srcTab, addrCont);
................................................................................
      int regData = 0;
      int flags = 0;
      if( pIdx->eIndexType==SQLITE_INDEX_PRIMARYKEY ){
        regData = regRec;
        flags = pik_flags;
      }
      sqlite4VdbeAddOp3(v, OP_IdxInsert, baseCur+i, regData, aRegIdx[i]);
      sqlite4VdbeChangeP5(v, flags);
    }
  }
}

/*
** Generate code that will open cursors for a table and for all
** indices of that table.  The "baseCur" parameter is the cursor number used

Changes to src/storage.c.

301
302
303
304
305
306
307








308
309
310
311
312
313
314
...
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363






364
365
366
367
368
369
370
371


372
373
374
375
376
377
378

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394

395
396
397
398
399
400
401
  return rc;
}

/*
** Key for the meta-data
*/
static const KVByteArray metadataKey[] = { 0x00, 0x00 };









/*
** Read nMeta unsigned 32-bit integers of metadata beginning at iStart.
*/
int sqlite4KVStoreGetMeta(KVStore *p, int iStart, int nMeta, unsigned int *a){
  KVCursor *pCur;
  int rc;
................................................................................
  KVStore *p,             /* Write to this database */
  int iStart,             /* Start writing here */
  int nMeta,              /* number of 32-bit integers to be written */
  unsigned int *a         /* The integers to write */
){
  KVCursor *pCur;
  int rc;
  int i, j;
  KVSize nData;
  const KVByteArray *aData;
  KVByteArray *aNew;
  KVSize nNew;


  rc = sqlite4KVStoreOpenCursor(p, &pCur);
  if( rc==SQLITE_OK ){






    rc = sqlite4KVCursorSeek(pCur, metadataKey, sizeof(metadataKey), 0);
    if( rc==SQLITE_OK ){
      rc = sqlite4KVCursorData(pCur, 0, -1, &aData, &nData);
    }else if( rc==SQLITE_NOTFOUND ){
      nData = 0;
      aData = 0;
      rc = SQLITE_OK;
    }


    if( rc==SQLITE_OK ){
      nNew = iStart+nMeta;
      if( nNew<nData ) nNew = nData;
      aNew = sqlite4DbMallocRaw(db, nNew*sizeof(a[0]) );
      if( aNew==0 ){
        rc = SQLITE_NOMEM;
      }else{

        memcpy(aNew, aData, nData);
        i = 0;
        j = iStart*4;
        while( i<nMeta && j+3<nData ){
          aNew[j] = (a[i]>>24)&0xff;
          aNew[j+1] = (a[i]>>16)&0xff;
          aNew[j+2] = (a[i]>>8)&0xff;
          aNew[j+3] = a[i] & 0xff;
          i++;
          j += 4;
        }
        rc = sqlite4KVStoreReplace(p, metadataKey, sizeof(metadataKey),
                                   aNew, nNew);
        sqlite4DbFree(db, aNew);
      }
    }

    sqlite4KVCursorClose(pCur);
  }
  return rc;
}

#if defined(SQLITE_DEBUG)
/*







>
>
>
>
>
>
>
>







 







<
<
<
<
<
>



>
>
>
>
>
>








>
>

|

|



>

<
|
|
<
<
<
<
<
<






>







301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
...
357
358
359
360
361
362
363





364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392

393
394






395
396
397
398
399
400
401
402
403
404
405
406
407
408
  return rc;
}

/*
** Key for the meta-data
*/
static const KVByteArray metadataKey[] = { 0x00, 0x00 };

static void writeMetaArray(KVByteArray *aMeta, int iElem, u32 iVal){
  int i = sizeof(u32) * iElem;
  aMeta[i+0] = (iVal>>24)&0xff;
  aMeta[i+1] = (iVal>>16)&0xff;
  aMeta[i+2] = (iVal>>8) &0xff;
  aMeta[i+3] = (iVal>>0) &0xff;
}

/*
** Read nMeta unsigned 32-bit integers of metadata beginning at iStart.
*/
int sqlite4KVStoreGetMeta(KVStore *p, int iStart, int nMeta, unsigned int *a){
  KVCursor *pCur;
  int rc;
................................................................................
  KVStore *p,             /* Write to this database */
  int iStart,             /* Start writing here */
  int nMeta,              /* number of 32-bit integers to be written */
  unsigned int *a         /* The integers to write */
){
  KVCursor *pCur;
  int rc;







  rc = sqlite4KVStoreOpenCursor(p, &pCur);
  if( rc==SQLITE_OK ){
    const KVByteArray *aData;     /* Original database meta-array value */
    KVSize nData;                 /* Size of aData[] in bytes */
    KVByteArray *aNew;            /* New database meta-array value */
    KVSize nNew;                  /* Size of aNew[] in bytes */

    /* Read the current meta-array value from the database */
    rc = sqlite4KVCursorSeek(pCur, metadataKey, sizeof(metadataKey), 0);
    if( rc==SQLITE_OK ){
      rc = sqlite4KVCursorData(pCur, 0, -1, &aData, &nData);
    }else if( rc==SQLITE_NOTFOUND ){
      nData = 0;
      aData = 0;
      rc = SQLITE_OK;
    }

    /* Encode and write the new meta-array value to the database */
    if( rc==SQLITE_OK ){
      nNew = sizeof(a[0]) * (iStart+nMeta);
      if( nNew<nData ) nNew = nData;
      aNew = sqlite4DbMallocRaw(db, nNew);
      if( aNew==0 ){
        rc = SQLITE_NOMEM;
      }else{
        int i;
        memcpy(aNew, aData, nData);

        for(i=iStart; i<iStart+nMeta; i++){
          writeMetaArray(aNew, i, a[i]);






        }
        rc = sqlite4KVStoreReplace(p, metadataKey, sizeof(metadataKey),
                                   aNew, nNew);
        sqlite4DbFree(db, aNew);
      }
    }

    sqlite4KVCursorClose(pCur);
  }
  return rc;
}

#if defined(SQLITE_DEBUG)
/*

Changes to src/update.c.

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
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






146
147
148
149
150
151
152
...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

188
189
190
191
192
193
194
...
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255
256
257
258
...
275
276
277
278
279
280
281
282













283
284
285
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
...
395
396
397
398
399
400
401




402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
...
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
...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  int nIdx;              /* Number of indices that need updating */
  int iCur;              /* VDBE Cursor number of pTab */
  sqlite4 *db;           /* The database structure */
  int *aRegIdx = 0;      /* One register assigned to each index to be updated */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  Expr *pRowidExpr = 0;  /* Expression defining the new record number */
  AuthContext sContext;  /* The authorization context */
  NameContext sNC;       /* The name-context to resolve expressions in */
  int iDb;               /* Database containing the table being updated */
  int okOnePass;         /* True for one-pass algorithm without the FIFO */
  int hasFK;             /* True if foreign key processing is required */

#ifndef SQLITE_OMIT_TRIGGER
................................................................................
  int tmask;             /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
#endif
  int newmask;           /* Mask of NEW.* columns accessed by BEFORE triggers */

  /* Register Allocations */
  int regOldKey;                  /* Register containing the original PK */

  int regRowCount = 0;   /* A count of rows changed */
  int regNewRowid;       /* The new rowid */
  int regNew;            /* Content of the NEW.* table in triggers */
  int regOld = 0;        /* Content of OLD.* table in triggers */


  int regKeySet = 0;              /* Register containing KeySet object */
  Index *pPk;                     /* The primary key index of this table */
  int iPk;                        /* Offset of primary key in aRegIdx[] */
  int bChngPk = 0;                /* True if any PK columns are updated */
  int bOpenAll = 0;               /* True if all indexes were opened */
  int bImplicitPk;                /* True if pTab has an implicit PK */



  memset(&sContext, 0, sizeof(sContext));
  db = pParse->db;
  if( pParse->nErr || db->mallocFailed ){
    goto update_cleanup;
  }
  assert( pSrc->nSrc==1 );

  /* Locate the table which we want to update. */






  pTab = sqlite4SrcListLookup(pParse, pSrc);
  if( pTab==0 ) goto update_cleanup;
  iDb = sqlite4SchemaToIndex(pParse->db, pTab->pSchema);
  pPk = sqlite4FindPrimaryKey(pTab, &iPk);
  bImplicitPk = (pPk->aiColumn[0]<0);

  /* Figure out if we have any triggers and if the table being
................................................................................
# define tmask 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif

  if( sqlite4ViewGetColumnNames(pParse, pTab) ){
    goto update_cleanup;
  }
  if( sqlite4IsReadOnly(pParse, pTab, tmask) ){
    goto update_cleanup;
  }
  aXRef = sqlite4DbMallocRaw(db, sizeof(int) * pTab->nCol );
  if( aXRef==0 ) goto update_cleanup;
  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;

  /* Allocate a cursors for the main database table and for all indices.
  ** The index cursors might not be used, but if they are used they
  ** need to occur right after the database cursor.  So go ahead and
  ** allocate enough space, just in case.
  */
  pSrc->a[0].iCursor = iCur = pParse->nTab++;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }


  /* Initialize the name-context */
  memset(&sNC, 0, sizeof(sNC));
  sNC.pParse = pParse;
  sNC.pSrcList = pSrc;

  /* Resolve the column names in all the expressions of the of the UPDATE 
................................................................................
  /* Begin generating code. */
  v = sqlite4GetVdbe(pParse);
  if( v==0 ) goto update_cleanup;
  if( pParse->nested==0 ) sqlite4VdbeCountChanges(v);
  sqlite4BeginWriteOperation(pParse, 1, iDb);

#ifndef SQLITE_OMIT_VIRTUALTABLE

  /* Virtual tables must be handled separately */
  if( IsVirtual(pTab) ){
    updateVirtualTable(pParse, pSrc, pTab, pChanges, pRowidExpr, aXRef,
                       pWhere, onError);
    pWhere = 0;
    pSrc = 0;
    goto update_cleanup;
  }
#endif

  hasFK = sqlite4FkRequired(pParse, pTab, aXRef);
................................................................................
          aRegIdx[j] = ++pParse->nMem;
          break;
        }
      }
    }
  }

  /* Allocate other required registers. */













  regKeySet = ++pParse->nMem;
  regOldKey = ++pParse->nMem;
  if( pTrigger || hasFK ){
    regOld = pParse->nMem + 1;

    pParse->nMem += pTab->nCol;
  }
#if 0
  if( chngRowid || pTrigger || hasFK ){
    regNewRowid = ++pParse->nMem;
  }
#endif
  if( bImplicitPk ) pParse->nMem++;
  regNew = pParse->nMem + 1;
  pParse->nMem += pTab->nCol;

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

  /* If we are trying to update a view, realize that view into
................................................................................
  ** KeySet object is bypassed and the primary key of the single row (if
  ** any) left in register regOldKey. This is called the "one-pass"
  ** approach. Set okOnePass to true if it can be used in this case.  */
  sqlite4VdbeAddOp3(v, OP_Null, 0, regKeySet, regOldKey);
  pWInfo = sqlite4WhereBegin(pParse, pSrc, pWhere, 0, 0, WHERE_ONEPASS_DESIRED);
  if( pWInfo==0 ) goto update_cleanup;
  okOnePass = pWInfo->okOnePass;
  sqlite4VdbeAddOp2(v, OP_RowKey, iCur, regOldKey);
  if( !okOnePass ){
    sqlite4VdbeAddOp2(v, OP_KeySetAdd, regKeySet, regOldKey);
  }
  sqlite4WhereEnd(pWInfo);

  /* Initialize the count of updated rows */
  if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
    regRowCount = ++pParse->nMem;
    sqlite4VdbeAddOp2(v, OP_Integer, 0, regRowCount);
  }

  /* Open every index that needs updating. If any index could potentially 
  ** invoke a REPLACE conflict resolution action, then we need to open all 
  ** indices because we might need to be deleting some records.  */
  if( !isView ){
    /* Set bOpenAll to true if this UPDATE might strike a REPLACE */
    bOpenAll = (onError==OE_Replace);
    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
................................................................................
  /* If there are triggers on this table, populate an array of registers 
  ** with the required old.* column data.  */
  if( hasFK || pTrigger ){
    u32 oldmask = (hasFK ? sqlite4FkOldmask(pParse, pTab) : 0);
    oldmask |= sqlite4TriggerColmask(pParse, 
        pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
    );




    for(i=0; i<pTab->nCol; i++){
      if( aXRef[i]<0 || oldmask==0xffffffff || (i<32 && (oldmask & (1<<i))) ){
        sqlite4ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld+i);
      }else{
        sqlite4VdbeAddOp2(v, OP_Null, 0, regOld+i);
      }
    }
#if 0
    if( chngRowid==0 ){
      sqlite4VdbeAddOp2(v, OP_Copy, regOldKey, regNewRowid);
    }
#endif
  }

  /* Populate the array of registers beginning at regNew with the new
  ** row data. This array is used to check constaints, create the new
  ** table and index records, and as the values for any new.* references
  ** made by triggers.
  **
................................................................................
  /* Fire any BEFORE UPDATE triggers. This happens before constraints are
  ** verified. One could argue that this is wrong.
  */
  if( tmask&TRIGGER_BEFORE ){
    sqlite4VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol);
    sqlite4TableAffinityStr(v, pTab);
    sqlite4CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
        TRIGGER_BEFORE, pTab, regOldKey, onError, addr);

    /* The row-trigger may have deleted the row being updated. In this
    ** case, jump to the next row. No updates or AFTER triggers are 
    ** required. This behaviour - what happens when the row being updated
    ** is deleted or renamed by a BEFORE trigger - is left undefined in the
    ** documentation.
    */
    sqlite4VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldKey);

    /* If it did not delete it, the row-trigger may still have modified 
    ** some of the columns of the row being updated. Load the values for 
    ** all columns not modified by the update statement into their 
    ** registers in case this has happened.
    */
    for(i=0; i<pTab->nCol; i++){
      if( aXRef[i]<0 ){
        sqlite4VdbeAddOp3(v, OP_Column, iCur, i, regNew+i);
        sqlite4ColumnDefault(v, pTab, i, regNew+i);
      }
    }
  }

  if( !isView ){
    int j1;                       /* Address of jump instruction */
................................................................................
    ** handle rows (possibly in other tables) that refer via a foreign key
    ** to the row just updated. */ 
    if( hasFK ){
      sqlite4FkActions(pParse, pTab, pChanges, regOldKey);
    }
  }

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

  sqlite4CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
      TRIGGER_AFTER, pTab, regOldKey, onError, addr);

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

  /* Close all tables */
  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    assert( aRegIdx );
    if( bOpenAll || aRegIdx[i] ){
      sqlite4VdbeAddOp2(v, OP_Close, iCur+i+1, 0);
    }
  }
  sqlite4VdbeAddOp2(v, OP_Close, iCur, 0);

  /* Update the sqlite_sequence table by storing the content of the
  ** maximum rowid counter values recorded while inserting into
  ** autoincrement tables.
  */
  if( pParse->nested==0 && pParse->pTriggerTab==0 ){
    sqlite4AutoincrementEnd(pParse);
  }

  /*
  ** Return the number of rows that were changed. If this routine is 
  ** generating code because of a call to sqlite4NestedParse(), do not
  ** invoke the callback function.
  */
  if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){
    sqlite4VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
    sqlite4VdbeSetNumCols(v, 1);
    sqlite4VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
  }

update_cleanup:
  sqlite4AuthContextPop(&sContext);
  sqlite4DbFree(db, aRegIdx);
  sqlite4DbFree(db, aXRef);
  sqlite4SrcListDelete(db, pSrc);
  sqlite4ExprListDelete(db, pChanges);
  sqlite4ExprDelete(db, pWhere);







<







 







<


<

>






>
>








|
>
>
>
>
>
>







 







|
<
<
|
<
|







|
<
|



>







 







>


|
<







 







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



|
>
|

<
<
<
<
<
|
|
|







 







|





<
<
<
<
<
<







 







>
>
>
>


|




<
<
<
<
<







 







|







|








|







 







<
<
<
<
<
<

|







|



|


<









<
<
<
<
<
<
<
<
<
<
<







102
103
104
105
106
107
108

109
110
111
112
113
114
115
...
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
146
147
148
149
150
151
152
153
154
155
156
157
158
...
168
169
170
171
172
173
174
175


176

177
178
179
180
181
182
183
184
185

186
187
188
189
190
191
192
193
194
195
196
197
...
244
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305





306
307
308
309
310
311
312
313
314
315
...
338
339
340
341
342
343
344
345
346
347
348
349
350






351
352
353
354
355
356
357
...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418





419
420
421
422
423
424
425
...
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
...
522
523
524
525
526
527
528






529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544

545
546
547
548
549
550
551
552
553











554
555
556
557
558
559
560
  int nIdx;              /* Number of indices that need updating */
  int iCur;              /* VDBE Cursor number of pTab */
  sqlite4 *db;           /* The database structure */
  int *aRegIdx = 0;      /* One register assigned to each index to be updated */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */

  AuthContext sContext;  /* The authorization context */
  NameContext sNC;       /* The name-context to resolve expressions in */
  int iDb;               /* Database containing the table being updated */
  int okOnePass;         /* True for one-pass algorithm without the FIFO */
  int hasFK;             /* True if foreign key processing is required */

#ifndef SQLITE_OMIT_TRIGGER
................................................................................
  int tmask;             /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
#endif
  int newmask;           /* Mask of NEW.* columns accessed by BEFORE triggers */

  /* Register Allocations */
  int regOldKey;                  /* Register containing the original PK */


  int regNewRowid;       /* The new rowid */
  int regNew;            /* Content of the NEW.* table in triggers */


  int regOld = 0;                 /* Content of OLD.* table in triggers */
  int regKeySet = 0;              /* Register containing KeySet object */
  Index *pPk;                     /* The primary key index of this table */
  int iPk;                        /* Offset of primary key in aRegIdx[] */
  int bChngPk = 0;                /* True if any PK columns are updated */
  int bOpenAll = 0;               /* True if all indexes were opened */
  int bImplicitPk;                /* True if pTab has an implicit PK */
  int regOldTr = 0;               /* Content of OLD.* table including IPK */
  int regNewTr = 0;               /* Content of NEW.* table including IPK */

  memset(&sContext, 0, sizeof(sContext));
  db = pParse->db;
  if( pParse->nErr || db->mallocFailed ){
    goto update_cleanup;
  }
  assert( pSrc->nSrc==1 );

  /* Locate and analyze the table to be updated. This block sets:
  **
  **   pTab
  **   iDb
  **   pPk
  **   bImplicitPk
  */
  pTab = sqlite4SrcListLookup(pParse, pSrc);
  if( pTab==0 ) goto update_cleanup;
  iDb = sqlite4SchemaToIndex(pParse->db, pTab->pSchema);
  pPk = sqlite4FindPrimaryKey(pTab, &iPk);
  bImplicitPk = (pPk->aiColumn[0]<0);

  /* Figure out if we have any triggers and if the table being
................................................................................
# define tmask 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif

  if( sqlite4ViewGetColumnNames(pParse, pTab) ) goto update_cleanup;


  if( sqlite4IsReadOnly(pParse, pTab, tmask) ) goto update_cleanup;


  aXRef = sqlite4DbMallocRaw(db, sizeof(int) * pTab->nCol );
  if( aXRef==0 ) goto update_cleanup;
  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;

  /* Allocate a cursors for the main database table and for all indices.
  ** The index cursors might not be used, but if they are used they
  ** need to occur right after the database cursor.  So go ahead and
  ** allocate enough space, just in case.  */

  iCur = pParse->nTab;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }
  pSrc->a[0].iCursor = iCur+iPk;

  /* Initialize the name-context */
  memset(&sNC, 0, sizeof(sNC));
  sNC.pParse = pParse;
  sNC.pSrcList = pSrc;

  /* Resolve the column names in all the expressions of the of the UPDATE 
................................................................................
  /* Begin generating code. */
  v = sqlite4GetVdbe(pParse);
  if( v==0 ) goto update_cleanup;
  if( pParse->nested==0 ) sqlite4VdbeCountChanges(v);
  sqlite4BeginWriteOperation(pParse, 1, iDb);

#ifndef SQLITE_OMIT_VIRTUALTABLE
  /* TODO: This is currently broken */
  /* Virtual tables must be handled separately */
  if( IsVirtual(pTab) ){
    updateVirtualTable(pParse, pSrc, pTab, pChanges, 0, aXRef, pWhere, onError);

    pWhere = 0;
    pSrc = 0;
    goto update_cleanup;
  }
#endif

  hasFK = sqlite4FkRequired(pParse, pTab, aXRef);
................................................................................
          aRegIdx[j] = ++pParse->nMem;
          break;
        }
      }
    }
  }

  /* Allocate other required registers. Specifically:
  **
  **     regKeySet:     1 register
  **     regOldKey:     1 register
  **     regOldTr:      nCol+1 registers
  **     regNewTr:      nCol+1 registers
  **
  ** The regOldTr allocation is only required if there are either triggers 
  ** or foreign keys to be processed.
  **
  ** The regOldTr and regNewTr register arrays include space for the 
  ** implicit primary key value if the table in question does not have an
  ** explicit PRIMARY KEY.
  */
  regKeySet = ++pParse->nMem;
  regOldKey = ++pParse->nMem;
  if( pTrigger || hasFK ){
    regOldTr = pParse->nMem + 1;
    regOld = regOldTr+1;
    pParse->nMem += (pTab->nCol + 1);
  }





  regNewTr = pParse->nMem + 1;
  regNew = regNewTr+1;
  pParse->nMem += (pTab->nCol+1);

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

  /* If we are trying to update a view, realize that view into
................................................................................
  ** KeySet object is bypassed and the primary key of the single row (if
  ** any) left in register regOldKey. This is called the "one-pass"
  ** approach. Set okOnePass to true if it can be used in this case.  */
  sqlite4VdbeAddOp3(v, OP_Null, 0, regKeySet, regOldKey);
  pWInfo = sqlite4WhereBegin(pParse, pSrc, pWhere, 0, 0, WHERE_ONEPASS_DESIRED);
  if( pWInfo==0 ) goto update_cleanup;
  okOnePass = pWInfo->okOnePass;
  sqlite4VdbeAddOp2(v, OP_RowKey, iCur+iPk, regOldKey);
  if( !okOnePass ){
    sqlite4VdbeAddOp2(v, OP_KeySetAdd, regKeySet, regOldKey);
  }
  sqlite4WhereEnd(pWInfo);







  /* Open every index that needs updating. If any index could potentially 
  ** invoke a REPLACE conflict resolution action, then we need to open all 
  ** indices because we might need to be deleting some records.  */
  if( !isView ){
    /* Set bOpenAll to true if this UPDATE might strike a REPLACE */
    bOpenAll = (onError==OE_Replace);
    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
................................................................................
  /* If there are triggers on this table, populate an array of registers 
  ** with the required old.* column data.  */
  if( hasFK || pTrigger ){
    u32 oldmask = (hasFK ? sqlite4FkOldmask(pParse, pTab) : 0);
    oldmask |= sqlite4TriggerColmask(pParse, 
        pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
    );

    if( bImplicitPk ){
      sqlite4VdbeAddOp2(v, OP_Rowid, iCur+iPk, regOldTr);
    }
    for(i=0; i<pTab->nCol; i++){
      if( aXRef[i]<0 || oldmask==0xffffffff || (i<32 && (oldmask & (1<<i))) ){
        sqlite4ExprCodeGetColumnOfTable(v, pTab, iCur+iPk, i, regOld+i);
      }else{
        sqlite4VdbeAddOp2(v, OP_Null, 0, regOld+i);
      }
    }





  }

  /* Populate the array of registers beginning at regNew with the new
  ** row data. This array is used to check constaints, create the new
  ** table and index records, and as the values for any new.* references
  ** made by triggers.
  **
................................................................................
  /* Fire any BEFORE UPDATE triggers. This happens before constraints are
  ** verified. One could argue that this is wrong.
  */
  if( tmask&TRIGGER_BEFORE ){
    sqlite4VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol);
    sqlite4TableAffinityStr(v, pTab);
    sqlite4CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
        TRIGGER_BEFORE, pTab, regOldTr, onError, addr);

    /* The row-trigger may have deleted the row being updated. In this
    ** case, jump to the next row. No updates or AFTER triggers are 
    ** required. This behaviour - what happens when the row being updated
    ** is deleted or renamed by a BEFORE trigger - is left undefined in the
    ** documentation.
    */
    sqlite4VdbeAddOp4Int(v, OP_NotFound, iCur+iPk, addr, regOldKey, 0);

    /* If it did not delete it, the row-trigger may still have modified 
    ** some of the columns of the row being updated. Load the values for 
    ** all columns not modified by the update statement into their 
    ** registers in case this has happened.
    */
    for(i=0; i<pTab->nCol; i++){
      if( aXRef[i]<0 ){
        sqlite4VdbeAddOp3(v, OP_Column, iCur+iPk, i, regNew+i);
        sqlite4ColumnDefault(v, pTab, i, regNew+i);
      }
    }
  }

  if( !isView ){
    int j1;                       /* Address of jump instruction */
................................................................................
    ** handle rows (possibly in other tables) that refer via a foreign key
    ** to the row just updated. */ 
    if( hasFK ){
      sqlite4FkActions(pParse, pTab, pChanges, regOldKey);
    }
  }







  sqlite4CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, 
      TRIGGER_AFTER, pTab, regOldTr, onError, addr);

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

  /* Close all cursors */
  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    assert( aRegIdx );
    if( bOpenAll || aRegIdx[i] ){
      sqlite4VdbeAddOp2(v, OP_Close, iCur+i, 0);
    }
  }


  /* Update the sqlite_sequence table by storing the content of the
  ** maximum rowid counter values recorded while inserting into
  ** autoincrement tables.
  */
  if( pParse->nested==0 && pParse->pTriggerTab==0 ){
    sqlite4AutoincrementEnd(pParse);
  }












update_cleanup:
  sqlite4AuthContextPop(&sContext);
  sqlite4DbFree(db, aRegIdx);
  sqlite4DbFree(db, aXRef);
  sqlite4SrcListDelete(db, pSrc);
  sqlite4ExprListDelete(db, pChanges);
  sqlite4ExprDelete(db, pWhere);

Changes to src/vdbe.c.

3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
....
3059
3060
3061
3062
3063
3064
3065


3066
3067
3068
3069
3070
3071
3072
3073
....
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
....
3761
3762
3763
3764
3765
3766
3767


3768
3769
3770
3771
3772

3773
3774
3775
3776
3777
3778
3779
....
4270
4271
4272
4273
4274
4275
4276

4277
4278
4279
4280
4281
4282
4283
** of the table. The contents of P4 are overwritten with an index key
** composed of the varint from the start of the initial blob content
** and the PRIMARY KEY values from the index entry causing the UNIQUE
** constraint to fail.
*/
case OP_IsUnique: {        /* jump, in3 */
  VdbeCursor *pC;
  Mem *pShort;
  Mem *pProbe;
  Mem *pOut;
  int iOut;
  int nShort;
  int dir;
  u64 dummy;

................................................................................
  );
  assert( nShort<=pProbe->n );
  assert( (nShort==pProbe->n)==(pC->pKeyInfo->nPK==0) );

  dir = (pC->pKeyInfo->nPK==0 ? 0 : 1);
  rc = sqlite4KVCursorSeek(pC->pKVCur, pProbe->z, nShort, dir);



  if( rc==SQLITE_NOTFOUND ){
    rc = SQLITE_OK;
    pc = pOp->p2-1;
  }else if( rc==SQLITE_INEXACT ){
    assert( nShort<pProbe->n );
    rc = sqlite4KVCursorKey(pC->pKVCur, &aKey, &nKey);
    if( rc==SQLITE_OK ){
      if( nKey<nShort 
................................................................................
  }
  break;
#endif

  /* If OMIT_MERGE_SORT is defined, fall through to IdxInsert. */
}

/* Opcode: IdxInsert P1 P2 P3 * *
**
** Register P3 holds the key and register P2 holds the data for an
** index entry.  Write this record into the index specified by the
** cursor P1.
*/
case OP_IdxInsert: {
  VdbeCursor *pC;
................................................................................
  pData = pOp->p2 ? &aMem[pOp->p2] : 0;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pC && pC->pKVCur && pC->pKVCur->pStore );
  assert( pKey->flags & MEM_Blob );
  assert( pData==0 || (pData->flags & MEM_Blob) );



  rc = sqlite4KVStoreReplace(
     pC->pKVCur->pStore,
     pKey->z, pKey->n,
     (pData ? pData->z : 0), (pData ? pData->n : 0)
  );

  break;
}

/* Opcode: IdxDelete P1 * P3 * *
**
** P1 is a cursor open on a database index. P3 contains a key suitable for
** the index. Delete P3 from P1.
................................................................................
** calling OP_Program instruction.
*/
case OP_Param: {           /* out2-prerelease */
  VdbeFrame *pFrame;
  Mem *pIn;
  pFrame = p->pFrame;
  pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];   

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

#endif /* #ifndef SQLITE_OMIT_TRIGGER */

#ifndef SQLITE_OMIT_FOREIGN_KEY







<







 







>
>
|







 







|







 







>
>





>







 







>







3032
3033
3034
3035
3036
3037
3038

3039
3040
3041
3042
3043
3044
3045
....
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
....
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
....
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
....
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
** of the table. The contents of P4 are overwritten with an index key
** composed of the varint from the start of the initial blob content
** and the PRIMARY KEY values from the index entry causing the UNIQUE
** constraint to fail.
*/
case OP_IsUnique: {        /* jump, in3 */
  VdbeCursor *pC;

  Mem *pProbe;
  Mem *pOut;
  int iOut;
  int nShort;
  int dir;
  u64 dummy;

................................................................................
  );
  assert( nShort<=pProbe->n );
  assert( (nShort==pProbe->n)==(pC->pKeyInfo->nPK==0) );

  dir = (pC->pKeyInfo->nPK==0 ? 0 : 1);
  rc = sqlite4KVCursorSeek(pC->pKVCur, pProbe->z, nShort, dir);

  if( rc==SQLITE_OK && pOut ){
    sqlite4VdbeMemCopy(pOut, pProbe);
  }else if( rc==SQLITE_NOTFOUND ){
    rc = SQLITE_OK;
    pc = pOp->p2-1;
  }else if( rc==SQLITE_INEXACT ){
    assert( nShort<pProbe->n );
    rc = sqlite4KVCursorKey(pC->pKVCur, &aKey, &nKey);
    if( rc==SQLITE_OK ){
      if( nKey<nShort 
................................................................................
  }
  break;
#endif

  /* If OMIT_MERGE_SORT is defined, fall through to IdxInsert. */
}

/* Opcode: IdxInsert P1 P2 P3 * P5
**
** Register P3 holds the key and register P2 holds the data for an
** index entry.  Write this record into the index specified by the
** cursor P1.
*/
case OP_IdxInsert: {
  VdbeCursor *pC;
................................................................................
  pData = pOp->p2 ? &aMem[pOp->p2] : 0;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pC && pC->pKVCur && pC->pKVCur->pStore );
  assert( pKey->flags & MEM_Blob );
  assert( pData==0 || (pData->flags & MEM_Blob) );

  if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;

  rc = sqlite4KVStoreReplace(
     pC->pKVCur->pStore,
     pKey->z, pKey->n,
     (pData ? pData->z : 0), (pData ? pData->n : 0)
  );

  break;
}

/* Opcode: IdxDelete P1 * P3 * *
**
** P1 is a cursor open on a database index. P3 contains a key suitable for
** the index. Delete P3 from P1.
................................................................................
** calling OP_Program instruction.
*/
case OP_Param: {           /* out2-prerelease */
  VdbeFrame *pFrame;
  Mem *pIn;
  pFrame = p->pFrame;
  pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];   
  assert( memIsValid(pIn) );
  sqlite4VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
  break;
}

#endif /* #ifndef SQLITE_OMIT_TRIGGER */

#ifndef SQLITE_OMIT_FOREIGN_KEY

Changes to src/vdbeaux.c.

1868
1869
1870
1871
1872
1873
1874





1875
1876
1877
1878
1879
1880
1881
          if( rc ){
            sqlite4RollbackAll(db);
            break;
          }
        }
      }
    }





  }

  /* We have successfully halted and closed the VM.  Record this fact. */
  if( p->pc>=0 ){
    db->activeVdbeCnt--;
    if( !p->readOnly ){
      db->writeVdbeCnt--;







>
>
>
>
>







1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
          if( rc ){
            sqlite4RollbackAll(db);
            break;
          }
        }
      }
    }

    if( p->changeCntOn ){
      sqlite4VdbeSetChanges(db, (eAction ? 0 : p->nChange));
    }
    p->nChange = 0;
  }

  /* We have successfully halted and closed the VM.  Record this fact. */
  if( p->pc>=0 ){
    db->activeVdbeCnt--;
    if( !p->readOnly ){
      db->writeVdbeCnt--;

Changes to src/vdbecodec.c.

109
110
111
112
113
114
115

116
117

118
119
120
121
122
123
124
125
    if( i<iVal ){
      ofst += size;
    }else if( type==0 ){
      /* no-op */
    }else if( type<=2 ){
      sqlite4VdbeMemSetInt64(pOut, type-1);
    }else if( type<=10 ){

      sqlite4_int64 v = ((char*)p->a)[ofst];
      for(i=4; i<type; i++){

        v = v*256 + p->a[ofst+i-3];
      }
      sqlite4VdbeMemSetInt64(pOut, v);
    }else if( type<=21 ){
      sqlite4_uint64 x;
      int e;
      double r;
      n = sqlite4GetVarint64(p->a+ofst, p->n-ofst, &x);







>

<
>
|







109
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
126
    if( i<iVal ){
      ofst += size;
    }else if( type==0 ){
      /* no-op */
    }else if( type<=2 ){
      sqlite4VdbeMemSetInt64(pOut, type-1);
    }else if( type<=10 ){
      int iByte;
      sqlite4_int64 v = ((char*)p->a)[ofst];

      for(iByte=1; iByte<size; iByte++){
        v = v*256 + p->a[ofst+iByte];
      }
      sqlite4VdbeMemSetInt64(pOut, v);
    }else if( type<=21 ){
      sqlite4_uint64 x;
      int e;
      double r;
      n = sqlite4GetVarint64(p->a+ofst, p->n-ofst, &x);

Changes to test/conflict.test.

355
356
357
358
359
360
361



362
363
364
365
366
367
368
    execsql "INSERT into t1 values($i,[expr {$i+1}]);"
  }
  execsql {
    SELECT count(*), min(a), max(b) FROM t1;
  }
} {50 1 51}
do_test conflict-7.2 {



  execsql {
    UPDATE OR IGNORE t1 SET a=1000;
  }
} {}
do_test conflict-7.2.1 {
  db changes
} {1}







>
>
>







355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
    execsql "INSERT into t1 values($i,[expr {$i+1}]);"
  }
  execsql {
    SELECT count(*), min(a), max(b) FROM t1;
  }
} {50 1 51}
do_test conflict-7.2 {
  explain {
    UPDATE OR IGNORE t1 SET a=1000;
  }
  execsql {
    UPDATE OR IGNORE t1 SET a=1000;
  }
} {}
do_test conflict-7.2.1 {
  db changes
} {1}

Changes to test/permutations.test.

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#   quick
#   full
#
lappend ::testsuitelist xxx

test_suite "src4" -prefix "" -description {
} -files [
  test_set simple.test fkey1.test conflict.test
]

test_suite "veryquick" -prefix "" -description {
  "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [







|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#   quick
#   full
#
lappend ::testsuitelist xxx

test_suite "src4" -prefix "" -description {
} -files [
  test_set simple.test fkey1.test conflict.test trigger2.test
]

test_suite "veryquick" -prefix "" -description {
  "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [

Changes to test/simple.test.

523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
















































































































551
552
553
554
555
556
557
#-------------------------------------------------------------------------
reset_db
do_execsql_test 25.1 {
  PRAGMA foreign_keys = on;
  CREATE TABLE p(x INT PRIMARY KEY);
  CREATE TABLE c(y REFERENCES p);
  INSERT INTO p VALUES(35);
PRAGMA vdbe_trace = 1;
  INSERT INTO c VALUES(35.0);
}
execsql { PRAGMA vdbe_trace = 0; }

explain {
  INSERT INTO c VALUES(35.0);
}
finish_test

#-------------------------------------------------------------------------
reset_db
do_execsql_test 26.1 {
  PRAGMA foreign_keys = on;
  CREATE TABLE p(x INT PRIMARY KEY);
  CREATE TABLE c(y REFERENCES p);
  INSERT INTO p VALUES(35.0);
  INSERT INTO c VALUES(35.0);
}

finish_test

















































































































#proc populate_t1 {} {
#  db eval {
#    INSERT INTO t1(a, b) VALUES(4, 'four');
#    INSERT INTO t1(a, b) VALUES(9, 'nine');
#    INSERT INTO t1(a, b) VALUES(5, 'five');
#    INSERT INTO t1(a, b) VALUES(1, 'one');







<


<

<
<
<
<
<










<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







523
524
525
526
527
528
529

530
531

532





533
534
535
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
#-------------------------------------------------------------------------
reset_db
do_execsql_test 25.1 {
  PRAGMA foreign_keys = on;
  CREATE TABLE p(x INT PRIMARY KEY);
  CREATE TABLE c(y REFERENCES p);
  INSERT INTO p VALUES(35);

  INSERT INTO c VALUES(35.0);
}







#-------------------------------------------------------------------------
reset_db
do_execsql_test 26.1 {
  PRAGMA foreign_keys = on;
  CREATE TABLE p(x INT PRIMARY KEY);
  CREATE TABLE c(y REFERENCES p);
  INSERT INTO p VALUES(35.0);
  INSERT INTO c VALUES(35.0);
}


#-------------------------------------------------------------------------
reset_db
do_execsql_test 27.1 {
  CREATE TABLE t1(a, b);
  CREATE TABLE log(x);
  CREATE TRIGGER BEFORE UPDATE ON t1 BEGIN
    INSERT INTO log VALUES(old.b || ' -> ' || new.b);
  END;
  INSERT INTO t1 VALUES(1, 'abc');
  UPDATE t1 SET b = 'xyz';
}
do_execsql_test 27.2 { SELECT * FROM log } {{abc -> xyz}}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 28.1 {
  CREATE TABLE t1(a, b);
  CREATE TABLE log(x);
  CREATE TRIGGER BEFORE UPDATE ON t1 BEGIN
    INSERT INTO log VALUES('rowid=' || old.rowid);
  END;
  INSERT INTO t1 VALUES(1, 'abc');
}

do_execsql_test 28.2 { SELECT rowid FROM t1 } 1
do_execsql_test 28.3 { UPDATE t1 SET b = 'xyz'; }
do_execsql_test 28.4 { SELECT * FROM log } {{rowid=1}}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 29.1 {
  CREATE TABLE t1(a, b);
  CREATE TABLE log(x,y,z);
  CREATE TRIGGER tr BEFORE INSERT ON t1 BEGIN
    INSERT INTO log VALUES(new.rowid, new.a, new.b);
  END;
}
do_execsql_test 29.2 { INSERT INTO t1 VALUES('one', 'abc') }
do_execsql_test 29.3 { SELECT * FROM log } {-1 one abc}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 30.1 {
  CREATE TABLE t1(a, b);
  CREATE TABLE log(x,y,z);
  CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
    INSERT INTO log VALUES(new.rowid, new.a, new.b);
  END;
}
do_execsql_test 30.2 { INSERT INTO t1 VALUES('one', 'abc') }
do_execsql_test 30.3 { SELECT * FROM log } {1 one abc}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 31.1 {
  CREATE TABLE tbl(a PRIMARY KEY, b, c);
  CREATE TRIGGER tr AFTER INSERT ON tbl BEGIN
    UPDATE tbl SET b = '';
  END;
  INSERT INTO tbl VALUES(1, 2, 3);
}

do_execsql_test 31.2 { SELECT * FROM tbl } {1 {} 3}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 32.1 {
  CREATE TABLE t1(a, b, c);
  INSERT INTO t1 VALUES(1, 2, 3);
}
do_execsql_test 32.2 { SELECT a, b, c FROM t1 } {1 2 3}
do_execsql_test 32.3 {
  DROP TABLE t1;
  CREATE TABLE t1(c, b, a);
  INSERT INTO t1 VALUES(1, 2, 3);
}
do_execsql_test 32.4 { SELECT a, b, c FROM t1 } {3 2 1}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 33.1 { CREATE TABLE t1(a, b, c) }
do_execsql_test 33.2 { CREATE TABLE t2(a, b, c) }
do_execsql_test 33.3 { CREATE TABLE t3(a, b, c) }
do_execsql_test 33.4 { CREATE TABLE t4(a, b, c) }

#-------------------------------------------------------------------------
reset_db
do_execsql_test 34.1 { CREATE TABLE t1(x PRIMARY KEY) }

do_execsql_test 34.2 { INSERT INTO t1 VALUES('123') }
do_test 34.3 { db changes } 1

do_execsql_test 34.4 { UPDATE t1 SET x = '456' }
do_test 34.5 { db changes } 1

do_execsql_test 34.6 { UPDATE t1 SET x = '456' WHERE x = '123' }
do_test 34.7 { db changes } 0

#-------------------------------------------------------------------------
reset_db
do_execsql_test 35.1 {
  CREATE TABLE tbl (a primary key, b, c);
  INSERT INTO tbl VALUES(1, 2, 3);
  INSERT INTO tbl VALUES(2, 2, 3);
  CREATE TRIGGER ai_tbl AFTER INSERT ON tbl BEGIN
    INSERT OR IGNORE INTO tbl values (new.a, 0, 0);
  END;
}

do_execsql_test 35.2 { INSERT OR REPLACE INTO tbl values (2, 2, 3) }
do_execsql_test 35.3 { SELECT * from tbl } {1 2 3 2 0 0}
  

#proc populate_t1 {} {
#  db eval {
#    INSERT INTO t1(a, b) VALUES(4, 'four');
#    INSERT INTO t1(a, b) VALUES(9, 'nine');
#    INSERT INTO t1(a, b) VALUES(5, 'five');
#    INSERT INTO t1(a, b) VALUES(1, 'one');

Changes to test/trigger2.test.

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
146
147
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
...
191
192
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
...
325
326
327
328
329
330
331

332
333
334
335
336
337
338
...
509
510
511
512
513
514
515

516
517
518
519
520
521

522
523
524
525
526
527
528
        INSERT INTO clog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM clog), 
  	  old.a, old.b, 
  	  (SELECT coalesce(sum(a),0) FROM tbl),
          (SELECT coalesce(sum(b),0) FROM tbl), 
  	  new.a, new.b);
      END;
    }
  
    do_test trigger2-1.$ii.1 {
      set r {}
      foreach v [execsql { 
        UPDATE tbl SET a = a * 10, b = b * 10;
        SELECT * FROM rlog ORDER BY idx;
        SELECT * FROM clog ORDER BY idx;
      }] {
        lappend r [expr {int($v)}]
      }
      set r
    } [list 1 1 2  4  6 10 20 \
            2 1 2 13 24 10 20 \
  	    3 3 4 13 24 30 40 \
  	    4 3 4 40 60 30 40 \
            1 1 2 13 24 10 20 ]

  
    execsql {
      DELETE FROM rlog;
      DELETE FROM tbl;
      INSERT INTO tbl VALUES (100, 100);
      INSERT INTO tbl VALUES (300, 200);
      CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW
................................................................................
        INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
  	  old.a, old.b, 
  	  (SELECT coalesce(sum(a),0) FROM tbl),
          (SELECT coalesce(sum(b),0) FROM tbl), 
  	  0, 0);
      END;
    }
    do_test trigger2-1.$ii.2 {
      set r {}
      foreach v [execsql {
        DELETE FROM tbl;
        SELECT * FROM rlog;
      }] {
        lappend r [expr {int($v)}]
      }
      set r
    } [list 1 100 100 400 300 0 0 \
            2 100 100 300 200 0 0 \
            3 300 200 300 200 0 0 \
            4 300 200 0 0 0 0 ]

  
    execsql {
      DELETE FROM rlog;
      CREATE TRIGGER insert_before_row BEFORE INSERT ON tbl FOR EACH ROW
        BEGIN
        INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
  	  0, 0,
................................................................................
        BEGIN
        INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
  	  0, 0,
  	  (SELECT coalesce(sum(a),0) FROM tbl),
          (SELECT coalesce(sum(b),0) FROM tbl), 
  	  new.a, new.b);
      END;
    }
    do_test trigger2-1.$ii.3 {
      execsql {
  
        CREATE TABLE other_tbl(a, b);
        INSERT INTO other_tbl VALUES(1, 2);
        INSERT INTO other_tbl VALUES(3, 4);



        -- INSERT INTO tbl SELECT * FROM other_tbl;
        INSERT INTO tbl VALUES(5, 6);
        DROP TABLE other_tbl;
  
        SELECT * FROM rlog;
      }
    } [list 1 0 0 0 0 5 6 \
            2 0 0 5 6 5 6 ]
  


    integrity_check trigger2-1.$ii.4
  }
  catchsql {
    DROP TABLE rlog;
    DROP TABLE clog;
    DROP TABLE tbl;
    DROP TABLE other_tbl;
................................................................................

    execsql "DELETE FROM tbl; DELETE FROM log; $prep";
    execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6]\
             ON tbl BEGIN $tr_program_fixed END;"

    do_test trigger2-2.$ii-after "execsql {$statement $query}" $after_data
    execsql "DROP TRIGGER the_trigger;"


    integrity_check trigger2-2.$ii-integrity
  }
}
catchsql {
  DROP TABLE tbl;
  DROP TABLE log;
................................................................................
    }
  } {1 {column a is not unique}}
  do_test trigger2-6.1e {
    execsql {
      SELECT * from tbl;
    }
  } {1 2 3 2 2 3}

  do_test trigger2-6.1f {
    execsql {
      INSERT OR REPLACE INTO tbl values (2, 2, 3);
      SELECT * from tbl;
    }
  } {1 2 3 2 0 0}

  do_test trigger2-6.1g {
    catchsql {
      INSERT OR ROLLBACK INTO tbl values (3, 2, 3);
    }
  } {1 {column a is not unique}}
  do_test trigger2-6.1h {
    execsql {







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







 







|
<
<


<
<
|
<
|
|
|
|
>







 







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







 







>







 







>






>







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
...
154
155
156
157
158
159
160
161


162
163


164

165
166
167
168
169
170
171
172
173
174
175
176
...
183
184
185
186
187
188
189
190



191
192
193
194
195
196
197
198


199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
        INSERT INTO clog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM clog), 
  	  old.a, old.b, 
  	  (SELECT coalesce(sum(a),0) FROM tbl),
          (SELECT coalesce(sum(b),0) FROM tbl), 
  	  new.a, new.b);
      END;
    }

    do_execsql_test trigger2-1.$ii.1 {


      UPDATE tbl SET a = a * 10, b = b * 10;
      SELECT * FROM rlog ORDER BY idx;
      SELECT * FROM clog ORDER BY idx;


    } {

      1 1 2  4  6 10 20
      2 1 2 13 24 10 20
      3 3 4 13 24 30 40
      4 3 4 40 60 30 40
      1 1 2 13 24 10 20
    }
  
    execsql {
      DELETE FROM rlog;
      DELETE FROM tbl;
      INSERT INTO tbl VALUES (100, 100);
      INSERT INTO tbl VALUES (300, 200);
      CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW
................................................................................
        INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
  	  old.a, old.b, 
  	  (SELECT coalesce(sum(a),0) FROM tbl),
          (SELECT coalesce(sum(b),0) FROM tbl), 
  	  0, 0);
      END;
    }
    do_execsql_test trigger2-1.$ii.2 {


        DELETE FROM tbl;
        SELECT * FROM rlog;


    } {

      1 100 100 400 300 0 0
      2 100 100 300 200 0 0
      3 300 200 300 200 0 0
      4 300 200 0 0 0 0 
    }
  
    execsql {
      DELETE FROM rlog;
      CREATE TRIGGER insert_before_row BEFORE INSERT ON tbl FOR EACH ROW
        BEGIN
        INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
  	  0, 0,
................................................................................
        BEGIN
        INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
  	  0, 0,
  	  (SELECT coalesce(sum(a),0) FROM tbl),
          (SELECT coalesce(sum(b),0) FROM tbl), 
  	  new.a, new.b);
      END;




      CREATE TABLE other_tbl(a, b);
      INSERT INTO other_tbl VALUES(1, 2);
      INSERT INTO other_tbl VALUES(3, 4);
    }

    do_execsql_test trigger2-1.$ii.3 {
      -- INSERT INTO tbl SELECT * FROM other_tbl;
      INSERT INTO tbl VALUES(5, 6);


      SELECT * FROM rlog;
    } {
      1 0 0 0 0 5 6
      2 0 0 5 6 5 6 
    }

    execsql { DROP TABLE other_tbl }
    integrity_check trigger2-1.$ii.4
  }
  catchsql {
    DROP TABLE rlog;
    DROP TABLE clog;
    DROP TABLE tbl;
    DROP TABLE other_tbl;
................................................................................

    execsql "DELETE FROM tbl; DELETE FROM log; $prep";
    execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6]\
             ON tbl BEGIN $tr_program_fixed END;"

    do_test trigger2-2.$ii-after "execsql {$statement $query}" $after_data
    execsql "DROP TRIGGER the_trigger;"


    integrity_check trigger2-2.$ii-integrity
  }
}
catchsql {
  DROP TABLE tbl;
  DROP TABLE log;
................................................................................
    }
  } {1 {column a is not unique}}
  do_test trigger2-6.1e {
    execsql {
      SELECT * from tbl;
    }
  } {1 2 3 2 2 3}

  do_test trigger2-6.1f {
    execsql {
      INSERT OR REPLACE INTO tbl values (2, 2, 3);
      SELECT * from tbl;
    }
  } {1 2 3 2 0 0}

  do_test trigger2-6.1g {
    catchsql {
      INSERT OR ROLLBACK INTO tbl values (3, 2, 3);
    }
  } {1 {column a is not unique}}
  do_test trigger2-6.1h {
    execsql {