SQLite

Check-in [0d236698e6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:STORED columns can now reference other STORED columns, in any order, as long as there are not loops.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | generated-columns
Files: files | file ages | folders
SHA3-256: 0d236698e64b2a4b46f91a25279c406e0bf392fe66116678456f0a034c11d7b4
User & Date: drh 2019-10-18 02:19:18.134
Context
2019-10-18
10:05
Get indexes working on virtual columns. (check-in: 450c48766c user: drh tags: generated-columns)
02:19
STORED columns can now reference other STORED columns, in any order, as long as there are not loops. (check-in: 0d236698e6 user: drh tags: generated-columns)
2019-10-17
18:35
In the Table object, change the nVCol field to nNVCol - the number of non-virtual columns, as that is the quantity that we need most. (check-in: 4ad66af04a user: drh tags: generated-columns)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
3573
3574
3575
3576
3577
3578
3579

3580





3581


3582
3583
3584


3585





3586




3587

3588










3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
          sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
                            &zAff[(aff-'B')*2], P4_STATIC);
        }
        return iReg;
      }
      if( iTab<0 ){
        if( pParse->iSelfTab<0 ){

          /* Generating CHECK constraints or inserting into partial index */





          assert( pExpr->y.pTab!=0 );


          assert( pExpr->iColumn>=XN_ROWID );
          assert( pExpr->iColumn<pExpr->y.pTab->nCol );
          if( pExpr->iColumn>=0


            && pExpr->y.pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL





          ){




            sqlite3VdbeAddOp2(v, OP_SCopy, pExpr->iColumn - pParse->iSelfTab,

                              target);










            sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
            return target;
          }else{
            return pExpr->iColumn - pParse->iSelfTab;
          }
        }else{
          /* Coding an expression that is part of an index where column names
          ** in the index refer to the table to which the index belongs */
          iTab = pParse->iSelfTab - 1;
        }
      }







>
|
>
>
>
>
>
|
>
>


|
>
>
|
>
>
>
>
>
|
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>



|







3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
          sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
                            &zAff[(aff-'B')*2], P4_STATIC);
        }
        return iReg;
      }
      if( iTab<0 ){
        if( pParse->iSelfTab<0 ){
          /* Other columns in the same row for CHECK constraints or
          ** generated columns or for inserting into partial index.
          ** The row is unpacked into registers beginning at
          ** 0-(pParse->iSelfTab).  The rowid (if any) is in a register
          ** immediately prior to the first column.
          */
          Column *pCol;
          Table *pTab = pExpr->y.pTab;
          int iSrc;
          assert( pTab!=0 );
          assert( pExpr->iColumn>=XN_ROWID );
          assert( pExpr->iColumn<pExpr->y.pTab->nCol );
          if( pExpr->iColumn<0 ){
            return -1-pParse->iSelfTab;
          }
          pCol = pTab->aCol + pExpr->iColumn;
          iSrc = sqlite3ColumnOfTable(pTab, pExpr->iColumn) - 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_VIRTUAL ){
              target = sqlite3ExprCodeTarget(pParse, pCol->pDflt, target);
            }else{
              target = iSrc;
              if( pCol->colFlags & COLFLAG_NOTAVAIL ){
                sqlite3ExprCode(pParse, pCol->pDflt, iSrc);
              }
            }
            pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL);
            return target;
          }else
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
          if( pCol->affinity==SQLITE_AFF_REAL ){
            sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target);
            sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
            return target;
          }else{
            return iSrc;
          }
        }else{
          /* Coding an expression that is part of an index where column names
          ** in the index refer to the table to which the index belongs */
          iTab = pParse->iSelfTab - 1;
        }
      }
Changes to src/insert.c.
211
212
213
214
215
216
217














218
219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
*/
void sqlite3ComputeStoredColumns(
  Parse *pParse,    /* Parsing context */
  int iRegStore,    /* Register holding the first column */
  Table *pTab       /* The table */
){
  int i;














  pParse->iSelfTab = -iRegStore;
  for(i=0; i<pTab->nCol; i++, iRegStore++){
    u32 colFlags = pTab->aCol[i].colFlags;
    if( (colFlags & COLFLAG_VIRTUAL)!=0 ){
      /* Virtual columns are not stored */
      iRegStore--;
    }else if( (colFlags & COLFLAG_STORED)!=0 ){
      /* Stored columns are handled on the second pass */
      sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);

    }
  }
  pParse->iSelfTab = 0;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */









>
>
>
>
>
>
>
>
>
>
>
>
>
>






|


>







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
*/
void sqlite3ComputeStoredColumns(
  Parse *pParse,    /* Parsing context */
  int iRegStore,    /* Register holding the first column */
  Table *pTab       /* The table */
){
  int i;
  /* Because there can be multiple STORED columns that refer to one another,
  ** either directly or through VIRTUAL columns, this is a two pass
  ** algorithm.  On the first pass, mark all STORED columns as NOT-AVAILABLE.
  */
  for(i=0; i<pTab->nCol; i++){
    if( pTab->aCol[i].colFlags & COLFLAG_STORED ){
      pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL;
    }
  }
  /* 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=0; i<pTab->nCol; i++, iRegStore++){
    u32 colFlags = pTab->aCol[i].colFlags;
    if( (colFlags & COLFLAG_VIRTUAL)!=0 ){
      /* Virtual columns are not stored */
      iRegStore--;
    }else if( (colFlags & COLFLAG_NOTAVAIL)!=0 ){
      /* Stored columns are handled on the second pass */
      sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
      colFlags &= ~COLFLAG_NOTAVAIL;
    }
  }
  pParse->iSelfTab = 0;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */


Changes to src/sqliteInt.h.
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843

1844
1845
1846
1847
1848
1849
1850
struct Column {
  char *zName;     /* Name of this column, \000, then the type */
  Expr *pDflt;     /* Default value or GENERATED ALWAYS AS value */
  char *zColl;     /* Collating sequence.  If NULL, use the default */
  u8 notNull;      /* An OE_ code for handling a NOT NULL constraint */
  char affinity;   /* One of the SQLITE_AFF_... values */
  u8 szEst;        /* Estimated size of value in this column. sizeof(INT)==1 */
  u8 colFlags;     /* Boolean properties.  See COLFLAG_ defines below */
};

/* Allowed values for Column.colFlags:
*/
#define COLFLAG_PRIMKEY   0x0001   /* Column is part of the primary key */
#define COLFLAG_HIDDEN    0x0002   /* A hidden column in a virtual table */
#define COLFLAG_HASTYPE   0x0004   /* Type name follows column name */
#define COLFLAG_UNIQUE    0x0008   /* Column def contains "UNIQUE" or "PK" */
#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 */

/*
** A "Collating Sequence" is defined by an instance of the following
** structure. Conceptually, a collating sequence consists of a name and
** a comparison routine that defines the order of that sequence.







|











|
>







1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
struct Column {
  char *zName;     /* Name of this column, \000, then the type */
  Expr *pDflt;     /* Default value or GENERATED ALWAYS AS value */
  char *zColl;     /* Collating sequence.  If NULL, use the default */
  u8 notNull;      /* An OE_ code for handling a NOT NULL constraint */
  char affinity;   /* One of the SQLITE_AFF_... values */
  u8 szEst;        /* Estimated size of value in this column. sizeof(INT)==1 */
  u16 colFlags;    /* Boolean properties.  See COLFLAG_ defines below */
};

/* Allowed values for Column.colFlags:
*/
#define COLFLAG_PRIMKEY   0x0001   /* Column is part of the primary key */
#define COLFLAG_HIDDEN    0x0002   /* A hidden column in a virtual table */
#define COLFLAG_HASTYPE   0x0004   /* Type name follows column name */
#define COLFLAG_UNIQUE    0x0008   /* Column def contains "UNIQUE" or "PK" */
#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 GENERATED columns */
#define COLFLAG_NOTAVAIL  0x0100   /* STORED column not yet calculated */
#define COLFLAG_GENERATED 0x0060   /* Combo: _STORED, _VIRTUAL */
#define COLFLAG_NOINSERT  0x0062   /* Combo: _HIDDEN, _STORED, _VIRTUAL */

/*
** A "Collating Sequence" is defined by an instance of the following
** structure. Conceptually, a collating sequence consists of a name and
** a comparison routine that defines the order of that sequence.