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 */