INSERT with named columns for a table with generated columns.
FossilOrigin-Name: 64db39f92d68d1b9f23e48af35e16b969c38b58041fbe900066eeb3ddb291cef
diff --git a/src/expr.c b/src/expr.c
index e02e146..c21006b 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3381,6 +3381,7 @@
int regOut /* Extract the value into this register */
){
Vdbe *v = pParse->pVdbe;
+ Column *pCol;
assert( v!=0 );
if( pTab==0 ){
sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
@@ -3395,11 +3396,17 @@
op = OP_VColumn;
x = iCol;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- }else if( pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL ){
- int savedSelfTab = pParse->iSelfTab;
- pParse->iSelfTab = iTabCur+1;
- sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, regOut);
- pParse->iSelfTab = savedSelfTab;
+ }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){
+ if( pCol->colFlags & COLFLAG_BUSY ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName);
+ }else{
+ int savedSelfTab = pParse->iSelfTab;
+ pCol->colFlags |= COLFLAG_BUSY;
+ pParse->iSelfTab = iTabCur+1;
+ sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, regOut);
+ pParse->iSelfTab = savedSelfTab;
+ pCol->colFlags &= ~COLFLAG_BUSY;
+ }
return;
#endif
}else if( !HasRowid(pTab) ){
diff --git a/src/insert.c b/src/insert.c
index 22c48d7..20b5d9a 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -130,7 +130,7 @@
** 'E' REAL
*/
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
- int i;
+ int i, j;
char *zColAff = pTab->zColAff;
if( zColAff==0 ){
sqlite3 *db = sqlite3VdbeDb(v);
@@ -140,13 +140,15 @@
return;
}
- for(i=0; i<pTab->nCol; i++){
+ for(i=j=0; i<pTab->nCol; i++){
assert( pTab->aCol[i].affinity!=0 );
- zColAff[i] = pTab->aCol[i].affinity;
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ zColAff[j++] = pTab->aCol[i].affinity;
+ }
}
do{
- zColAff[i--] = 0;
- }while( i>=0 && zColAff[i]<=SQLITE_AFF_BLOB );
+ zColAff[j--] = 0;
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
pTab->zColAff = zColAff;
}
assert( zColAff!=0 );
@@ -1006,6 +1008,9 @@
nHidden = 0;
iRegStore = regRowid+1;
for(i=0; i<pTab->nCol; i++, iRegStore++){
+ int k;
+ assert( i>=nHidden );
+ assert( iRegStore==sqlite3ColumnOfTable(pTab,i)+regRowid+1 );
if( i==pTab->iPKey ){
/* The value of the INTEGER PRIMARY KEY column is always a NULL.
** Whenever this column is read, the rowid will be substituted
@@ -1015,32 +1020,41 @@
sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
continue;
}
- if( pColumn==0 ){
- if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ){
- j = -1;
- nHidden++;
- if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
- iRegStore--;
- continue;
- }
+ if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ){
+ nHidden++;
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
+ /* Virtual columns are no stored */
+ iRegStore--;
}else{
- j = i - nHidden;
+ /* Hidden and stored columns get the default value */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
}
- }else{
- for(j=0; j<pColumn->nId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
+ continue;
}
- if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
+ if( pColumn ){
+ for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){}
+ if( j>=pColumn->nId ){
+ /* A column not named in the insert column list gets its
+ ** default value */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }
+ k = j;
+ }else if( nColumn==0 ){
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
- }else if( useTempTable ){
- sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
+ continue;
+ }else{
+ k = i - nHidden;
+ }
+
+ if( useTempTable ){
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
}else if( pSelect ){
if( regFromSelect!=regData ){
- sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
+ sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
}
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index eb815a7..8455155 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1840,6 +1840,7 @@
#define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */
#define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */
#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */
+#define COLFLAG_BUSY 0x0080 /* Blocks recursion on VIRTUAL columns */
#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */