aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-10-22 13:59:23 +0000
committerdrh <drh@noemail.net>2019-10-22 13:59:23 +0000
commit7e7fd73b25f83b6aac246a79990e0f5ff3019e7c (patch)
tree7a30e21c01a4b291041dc3c498df85a4dd4ce9b7 /src
parent427b96aedf422b1a8e906e47e8852033c70939c4 (diff)
downloadsqlite-7e7fd73b25f83b6aac246a79990e0f5ff3019e7c.tar.gz
sqlite-7e7fd73b25f83b6aac246a79990e0f5ff3019e7c.zip
In UPDATE processing, include generated columns in the set of columns being
updated if and only if their generator expressions reference some other column that is being updated. FossilOrigin-Name: d38176e93a628e03f1bd8b689fbc4152a1495388da917c2d89cefed04353d2d6
Diffstat (limited to 'src')
-rw-r--r--src/build.c10
-rw-r--r--src/update.c28
2 files changed, 36 insertions, 2 deletions
diff --git a/src/build.c b/src/build.c
index 2ba939822..efdcb59b1 100644
--- a/src/build.c
+++ b/src/build.c
@@ -1405,6 +1405,12 @@ void sqlite3AddDefaultValue(
if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colflags & COLFLAG_VIRTUAL );
+ testcase( pCol->colflags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column");
+#endif
}else{
/* A copy of pExpr is used instead of the original, as pExpr contains
** tokens that point to volatile memory.
@@ -1633,14 +1639,14 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){
goto generated_done;
generated_error:
- sqlite3ErrorMsg(pParse, "incorrect GENERATED ALWAYS AS on column \"%s\"",
+ sqlite3ErrorMsg(pParse, "error in generated column \"%s\"",
pCol->zName);
generated_done:
sqlite3ExprDelete(pParse->db, pExpr);
#else
/* Throw and error for the GENERATED ALWAYS AS clause if the
** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */
- sqlite3ErrorMsg(pParse, "GENERATED ALWAYS AS not supported");
+ sqlite3ErrorMsg(pParse, "generated columns not supported");
sqlite3ExprDelete(pParse->db, pExpr);
#endif
}
diff --git a/src/update.c b/src/update.c
index 48413a0df..d690b69f9 100644
--- a/src/update.c
+++ b/src/update.c
@@ -356,6 +356,33 @@ void sqlite3Update(
assert( chngPk==0 || chngPk==1 );
chngKey = chngRowid + chngPk;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Mark generated columns as changing if their generator expressions
+ ** reference any changing column. The actual aXRef[] value for
+ ** generated expressions is not used, other than to check to see that it
+ ** is non-negative, so the value of aXRef[] for generated columns can be
+ ** set to any non-negative number. We use 99999 so that the value is
+ ** obvious when looking at aXRef[] in a symbolic debugger.
+ */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ int bProgress;
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ do{
+ bProgress = 0;
+ for(i=0; i<pTab->nCol; i++){
+ if( aXRef[i]>=0 ) continue;
+ if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue;
+ if( sqlite3ExprReferencesUpdatedColumn(pTab->aCol[i].pDflt,
+ aXRef, chngRowid) ){
+ aXRef[i] = 99999;
+ bProgress = 1;
+ }
+ }
+ }while( bProgress );
+ }
+#endif
+
/* The SET expressions are not actually used inside the WHERE loop.
** So reset the colUsed mask. Unless this is a virtual table. In that
** case, set all bits of the colUsed mask (to ensure that the virtual
@@ -952,6 +979,7 @@ static void updateVirtualTable(
/* Populate the argument registers. */
for(i=0; i<pTab->nCol; i++){
+ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
}else{