diff options
author | drh <drh@noemail.net> | 2019-10-22 13:59:23 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-10-22 13:59:23 +0000 |
commit | 7e7fd73b25f83b6aac246a79990e0f5ff3019e7c (patch) | |
tree | 7a30e21c01a4b291041dc3c498df85a4dd4ce9b7 /src | |
parent | 427b96aedf422b1a8e906e47e8852033c70939c4 (diff) | |
download | sqlite-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.c | 10 | ||||
-rw-r--r-- | src/update.c | 28 |
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{ |