/ Check-in [c21959d4]
Login

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

Overview
Comment:Basic UPDATE functionality working for VIRTUAL columns.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | generated-columns
Files: files | file ages | folders
SHA3-256: c21959d4eb5d742a097a98e1874c0bf132dc962a97a65be1ab22d6ca3cf2b261
User & Date: drh 2019-10-17 15:59:03
Original Comment: Basic UPDATE functionality working for VIRTUAL tables.
Context
2019-10-17
16:16
Fix the xfer optimization for generated columns, so that VACUUM works again. check-in: 8f67b89b user: drh tags: generated-columns
15:59
Basic UPDATE functionality working for VIRTUAL columns. check-in: c21959d4 user: drh tags: generated-columns
14:21
Bug fixes so that "make test" once against runs with no errors. check-in: 7bfe0f67 user: drh tags: generated-columns
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/update.c.

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
304
305
306
307
308
309
310








311
312
313
314
315
316
317
...
619
620
621
622
623
624
625
626





627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
...
651
652
653
654
655
656
657
658
659
660


661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
...
704
705
706
707
708
709
710
711


712
713
714
715
716
717
718
719
720
  ExprList *pChanges,    /* Things to be changed */
  Expr *pWhere,          /* The WHERE clause.  May be null */
  int onError,           /* How to handle constraint errors */
  ExprList *pOrderBy,    /* ORDER BY clause. May be null */
  Expr *pLimit,          /* LIMIT clause. May be null */
  Upsert *pUpsert        /* ON CONFLICT clause, or null */
){
  int i, j;              /* Loop counters */
  Table *pTab;           /* The table to be updated */
  int addrTop = 0;       /* VDBE instruction address of the start of the loop */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Vdbe *v;               /* The virtual database engine */
  Index *pIdx;           /* For looping over indices */
  Index *pPk;            /* The PRIMARY KEY index for WITHOUT ROWID tables */
  int nIdx;              /* Number of indices that need updating */
................................................................................
      if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
        if( j==pTab->iPKey ){
          chngRowid = 1;
          pRowidExpr = pChanges->a[i].pExpr;
        }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
          chngPk = 1;
        }








        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){
        j = -1;
................................................................................
  /* Compute the old pre-UPDATE content of the row being changed, if that
  ** information is needed */
  if( chngPk || hasFK || pTrigger ){
    u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
    oldmask |= sqlite3TriggerColmask(pParse, 
        pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
    );
    for(i=0; i<pTab->nCol; i++){





      if( oldmask==0xffffffff
       || (i<32 && (oldmask & MASKBIT32(i))!=0)
       || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0
      ){
        testcase(  oldmask!=0xffffffff && i==31 );
        sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regOld+i);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
      }
    }
    if( chngRowid==0 && pPk==0 ){
      sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
    }
  }

................................................................................
  ** the database after the BEFORE triggers are fired anyway (as the trigger 
  ** may have modified them). So not loading those that are not going to
  ** be used eliminates some redundant opcodes.
  */
  newmask = sqlite3TriggerColmask(
      pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
  );
  for(i=0; i<pTab->nCol; i++){
    if( i==pTab->iPKey ){
      sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);


    }else{
      j = aXRef[i];
      if( j>=0 ){
        sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
      }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
        /* This branch loads the value of a column that will not be changed 
        ** into a register. This is done if there are no BEFORE triggers, or
        ** if there are one or more BEFORE triggers that use this value via
        ** a new.* reference in a trigger program.
        */
        testcase( i==31 );
        testcase( i==32 );
        sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regNew+i);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
      }
    }
  }

  /* Fire any BEFORE UPDATE triggers. This happens before constraints are
  ** verified. One could argue that this is wrong.
  */
................................................................................
    ** 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. Only unmodified columns are reloaded.
    ** The values computed for modified columns use the values before the
    ** BEFORE trigger runs.  See test case trigger1-18.0 (added 2018-04-26)
    ** for an example.
    */
    for(i=0; i<pTab->nCol; i++){


      if( aXRef[i]<0 && i!=pTab->iPKey ){
        sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regNew+i);
      }
    }
  }

  if( !isView ){
    /* Do constraint checks. */
    assert( regOldRowid>0 );







|







 







>
>
>
>
>
>
>
>







 







|
>
>
>
>
>


|


|

|







 







|

|
>
>



|








|

|







 







|
>
>
|
|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
...
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
...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
...
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  ExprList *pChanges,    /* Things to be changed */
  Expr *pWhere,          /* The WHERE clause.  May be null */
  int onError,           /* How to handle constraint errors */
  ExprList *pOrderBy,    /* ORDER BY clause. May be null */
  Expr *pLimit,          /* LIMIT clause. May be null */
  Upsert *pUpsert        /* ON CONFLICT clause, or null */
){
  int i, j, k;           /* Loop counters */
  Table *pTab;           /* The table to be updated */
  int addrTop = 0;       /* VDBE instruction address of the start of the loop */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Vdbe *v;               /* The virtual database engine */
  Index *pIdx;           /* For looping over indices */
  Index *pPk;            /* The PRIMARY KEY index for WITHOUT ROWID tables */
  int nIdx;              /* Number of indices that need updating */
................................................................................
      if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
        if( j==pTab->iPKey ){
          chngRowid = 1;
          pRowidExpr = pChanges->a[i].pExpr;
        }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
          chngPk = 1;
        }
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
        else if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
          sqlite3ErrorMsg(pParse, 
             "cannot UPDATE generated column \"%s\"",
             pTab->aCol[j].zName);
          goto update_cleanup;
        }
#endif
        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){
        j = -1;
................................................................................
  /* Compute the old pre-UPDATE content of the row being changed, if that
  ** information is needed */
  if( chngPk || hasFK || pTrigger ){
    u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
    oldmask |= sqlite3TriggerColmask(pParse, 
        pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
    );
    for(i=0, k=regOld; i<pTab->nCol; i++, k++){
      u32 colFlags = pTab->aCol[i].colFlags;
      if( colFlags & COLFLAG_VIRTUAL ){
        k--;
        continue;
      }
      if( oldmask==0xffffffff
       || (i<32 && (oldmask & MASKBIT32(i))!=0)
       || (colFlags & COLFLAG_PRIMKEY)!=0
      ){
        testcase(  oldmask!=0xffffffff && i==31 );
        sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, k);
      }
    }
    if( chngRowid==0 && pPk==0 ){
      sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
    }
  }

................................................................................
  ** the database after the BEFORE triggers are fired anyway (as the trigger 
  ** may have modified them). So not loading those that are not going to
  ** be used eliminates some redundant opcodes.
  */
  newmask = sqlite3TriggerColmask(
      pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
  );
  for(i=0, k=regNew; i<pTab->nCol; i++, k++){
    if( i==pTab->iPKey ){
      sqlite3VdbeAddOp2(v, OP_Null, 0, k);
    }else if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)!=0 ){
      k--;
    }else{
      j = aXRef[i];
      if( j>=0 ){
        sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
      }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
        /* This branch loads the value of a column that will not be changed 
        ** into a register. This is done if there are no BEFORE triggers, or
        ** if there are one or more BEFORE triggers that use this value via
        ** a new.* reference in a trigger program.
        */
        testcase( i==31 );
        testcase( i==32 );
        sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, k);
      }
    }
  }

  /* Fire any BEFORE UPDATE triggers. This happens before constraints are
  ** verified. One could argue that this is wrong.
  */
................................................................................
    ** 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. Only unmodified columns are reloaded.
    ** The values computed for modified columns use the values before the
    ** BEFORE trigger runs.  See test case trigger1-18.0 (added 2018-04-26)
    ** for an example.
    */
    for(i=0, k=regNew; i<pTab->nCol; i++, k++){
      if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
        k--;
      }else if( aXRef[i]<0 && i!=pTab->iPKey ){
        sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k);
      }
    }
  }

  if( !isView ){
    /* Do constraint checks. */
    assert( regOldRowid>0 );