diff options
author | drh <drh@noemail.net> | 2019-11-06 22:19:07 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-11-06 22:19:07 +0000 |
commit | dfa15270c4108fedd817a99751fc73d43d7fb29d (patch) | |
tree | 4af010f447a0616bdb822a84834455516cd9f956 /src | |
parent | bde3a4f680b7c99ae918aa0477e81541ebdafbe5 (diff) | |
download | sqlite-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.c | 11 | ||||
-rw-r--r-- | src/insert.c | 59 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 |
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; }; |