diff options
Diffstat (limited to 'src/insert.c')
-rw-r--r-- | src/insert.c | 59 |
1 files changed, 43 insertions, 16 deletions
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; } |