aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2019-11-06 22:19:07 +0000
committerdrh <drh@noemail.net>2019-11-06 22:19:07 +0000
commitdfa15270c4108fedd817a99751fc73d43d7fb29d (patch)
tree4af010f447a0616bdb822a84834455516cd9f956 /src
parentbde3a4f680b7c99ae918aa0477e81541ebdafbe5 (diff)
downloadsqlite-dfa15270c4108fedd817a99751fc73d43d7fb29d.tar.gz
sqlite-dfa15270c4108fedd817a99751fc73d43d7fb29d.zip
Change the way generated columns are computed so that no column is computed
inside branch code that might not be taken. Ticket [4fc08501f4e56692] FossilOrigin-Name: 9e07b48934e9a972dcf62e3538b3b21ffa044c553feba0441675ac0bbe13bcb2
Diffstat (limited to 'src')
-rw-r--r--src/expr.c11
-rw-r--r--src/insert.c59
-rw-r--r--src/sqliteInt.h3
3 files changed, 46 insertions, 27 deletions
diff --git a/src/expr.c b/src/expr.c
index 093736f39..330e057a0 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3645,16 +3645,7 @@ expr_code_doover:
iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( pCol->colFlags & COLFLAG_GENERATED ){
- if( pCol->colFlags & COLFLAG_BUSY ){
- sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"",
- pCol->zName);
- return 0;
- }
- pCol->colFlags |= COLFLAG_BUSY;
- if( pCol->colFlags & COLFLAG_NOTAVAIL ){
- sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc);
- }
- pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL);
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc);
return iSrc;
}else
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
diff --git a/src/insert.c b/src/insert.c
index 77edc5ea6..d8d369529 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -201,6 +201,16 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
return 0;
}
+/* This walker callback will compute the union of colFlags flags for all
+** references columns in a CHECK constraint or generated column expression.
+*/
+static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN ){
+ pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags;
+ }
+ return WRC_Continue;
+}
+
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/*
** All regular columns for table pTab have been puts into registers
@@ -215,7 +225,10 @@ void sqlite3ComputeGeneratedColumns(
Table *pTab /* The table */
){
int i;
- int nv;
+ Walker w;
+ Column *pRedo;
+ int eProgress;
+
/* Because there can be multiple generated columns that refer to one another,
** this is a two-pass algorithm. On the first pass, mark all generated
** columns as "not available".
@@ -227,29 +240,43 @@ void sqlite3ComputeGeneratedColumns(
pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL;
}
}
+
+ w.u.pTab = pTab;
+ w.xExprCallback = exprColumnFlagUnion;
+ w.xSelectCallback = 0;
+ w.xSelectCallback2 = 0;
+
/* On the second pass, compute the value of each NOT-AVAILABLE column.
** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will
** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as
** they are needed.
*/
pParse->iSelfTab = -iRegStore;
- for(i=nv=0; i<pTab->nCol; i++){
- u32 colFlags = pTab->aCol[i].colFlags;
- if( (colFlags & COLFLAG_NOTAVAIL)!=0 ){
- assert( colFlags & COLFLAG_GENERATED );
- if( colFlags & COLFLAG_VIRTUAL ){
- /* Virtual columns go at the end */
- assert( pTab->nNVCol+nv == sqlite3TableColumnToStorage(pTab,i) );
- sqlite3ExprCodeGeneratedColumn(pParse, &pTab->aCol[i],
- iRegStore+pTab->nNVCol+nv);
- }else{
- /* Stored columns go in column order */
- assert( i-nv == sqlite3TableColumnToStorage(pTab,i) );
- sqlite3ExprCodeGeneratedColumn(pParse, &pTab->aCol[i], iRegStore+i-nv);
+ do{
+ eProgress = 0;
+ pRedo = 0;
+ for(i=0; i<pTab->nCol; i++){
+ Column *pCol = pTab->aCol + i;
+ if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){
+ int x;
+ pCol->colFlags |= COLFLAG_BUSY;
+ w.eCode = 0;
+ sqlite3WalkExpr(&w, pCol->pDflt);
+ pCol->colFlags &= ~COLFLAG_BUSY;
+ if( w.eCode & COLFLAG_NOTAVAIL ){
+ pRedo = pCol;
+ continue;
+ }
+ eProgress = 1;
+ assert( pCol->colFlags & COLFLAG_GENERATED );
+ x = sqlite3TableColumnToStorage(pTab, i) + iRegStore;
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, x);
+ pCol->colFlags &= ~COLFLAG_NOTAVAIL;
}
- pTab->aCol[i].colFlags &= ~COLFLAG_NOTAVAIL;
}
- if( (colFlags & COLFLAG_VIRTUAL)!=0 ) nv++;
+ }while( pRedo && eProgress );
+ if( pRedo ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zName);
}
pParse->iSelfTab = 0;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index cf7abfe66..b12391a3e 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3546,7 +3546,7 @@ struct Walker {
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
- u8 eCode; /* A small processing code */
+ u16 eCode; /* A small processing code */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int n; /* A counter */
@@ -3562,6 +3562,7 @@ struct Walker {
struct WindowRewrite *pRewrite; /* Window rewrite context */
struct WhereConst *pConst; /* WHERE clause constants */
struct RenameCtx *pRename; /* RENAME COLUMN context */
+ struct Table *pTab; /* Table of generated column */
} u;
};