diff options
author | drh <drh@noemail.net> | 2019-10-16 20:05:56 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-10-16 20:05:56 +0000 |
commit | c27ea2ae8df4207e6b2479b46904c73d7cd1775f (patch) | |
tree | 4adc4abd49f11e21bbb8ecbbeb081a5ad90df11f /src | |
parent | 7e508f1ee2d671976fd1dbe4a8fdbc840ba39b97 (diff) | |
download | sqlite-c27ea2ae8df4207e6b2479b46904c73d7cd1775f.tar.gz sqlite-c27ea2ae8df4207e6b2479b46904c73d7cd1775f.zip |
ALTER TABLE is able to add a VIRTUAL column.
FossilOrigin-Name: 120c6b78cb51532f783014605f1107d40b2e4f54e3852fb1f8f167d0c0b78c69
Diffstat (limited to 'src')
-rw-r--r-- | src/alter.c | 67 | ||||
-rw-r--r-- | src/build.c | 2 | ||||
-rw-r--r-- | src/insert.c | 6 | ||||
-rw-r--r-- | src/sqliteInt.h | 1 |
4 files changed, 41 insertions, 35 deletions
diff --git a/src/alter.c b/src/alter.c index 9d02d3835..f8cada0e3 100644 --- a/src/alter.c +++ b/src/alter.c @@ -298,14 +298,6 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ } #endif - /* If the default value for the new column was specified with a - ** literal NULL, then set pDflt to 0. This simplifies checking - ** for an SQL NULL default below. - */ - assert( pDflt==0 || pDflt->op==TK_SPAN ); - if( pDflt && pDflt->pLeft->op==TK_NULL ){ - pDflt = 0; - } /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the @@ -319,36 +311,47 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } - if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a REFERENCES column with non-NULL default value"); - return; - } - if( pCol->notNull && !pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a NOT NULL column with default value NULL"); - return; - } - - /* Ensure the default expression is something that sqlite3ValueFromExpr() - ** can handle (i.e. not CURRENT_TIME etc.) - */ - if( pDflt ){ - sqlite3_value *pVal = 0; - int rc; - rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); - assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); - if( rc!=SQLITE_OK ){ - assert( db->mallocFailed == 1 ); + if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){ + /* If the default value for the new column was specified with a + ** literal NULL, then set pDflt to 0. This simplifies checking + ** for an SQL NULL default below. + */ + assert( pDflt==0 || pDflt->op==TK_SPAN ); + if( pDflt && pDflt->pLeft->op==TK_NULL ){ + pDflt = 0; + } + if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ + sqlite3ErrorMsg(pParse, + "Cannot add a REFERENCES column with non-NULL default value"); return; } - if( !pVal ){ - sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); + if( pCol->notNull && !pDflt ){ + sqlite3ErrorMsg(pParse, + "Cannot add a NOT NULL column with default value NULL"); return; } - sqlite3ValueFree(pVal); + + /* Ensure the default expression is something that sqlite3ValueFromExpr() + ** can handle (i.e. not CURRENT_TIME etc.) + */ + if( pDflt ){ + sqlite3_value *pVal = 0; + int rc; + rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc!=SQLITE_OK ){ + assert( db->mallocFailed == 1 ); + return; + } + if( !pVal ){ + sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default"); + return; + } + sqlite3ValueFree(pVal); + } } + /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ diff --git a/src/build.c b/src/build.c index 7e1f3b40c..897e9183e 100644 --- a/src/build.c +++ b/src/build.c @@ -1570,7 +1570,7 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ goto generated_done; generated_error: - sqlite3ErrorMsg(pParse, "bad GENERATED ALWAYS AS clause on column \"%s\"", + sqlite3ErrorMsg(pParse, "incorrect GENERATED ALWAYS AS on column \"%s\"", pCol->zName); generated_done: sqlite3ExprDelete(pParse->db, pExpr); diff --git a/src/insert.c b/src/insert.c index f2ed9d9a3..22c48d7f3 100644 --- a/src/insert.c +++ b/src/insert.c @@ -532,6 +532,7 @@ void sqlite3Insert( u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ + int iRegStore; /* Register in which to store next column */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ @@ -1003,8 +1004,8 @@ void sqlite3Insert( ** with the first column. */ nHidden = 0; - for(i=0; i<pTab->nCol; i++){ - int iRegStore = regRowid+1+i; + iRegStore = regRowid+1; + for(i=0; i<pTab->nCol; i++, iRegStore++){ 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 @@ -1019,6 +1020,7 @@ void sqlite3Insert( j = -1; nHidden++; if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + iRegStore--; continue; } }else{ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 94d7107a0..eb815a79e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1840,6 +1840,7 @@ struct Column { #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_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ /* |