Support for a future ALTER TABLE command to add columns with default values. (CVS 2367)
FossilOrigin-Name: 9d5abc1ddf6da37563c12d5a0401b89bb4e51c59
diff --git a/src/delete.c b/src/delete.c
index b160bda..43445ff 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
-** $Id: delete.c,v 1.100 2005/01/29 08:32:45 danielk1977 Exp $
+** $Id: delete.c,v 1.101 2005/03/09 12:26:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -436,6 +436,7 @@
sqlite3VdbeAddOp(v, OP_Dup, j, 0);
}else{
sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
+ sqlite3ColumnDefault(v, pTab, idx);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
diff --git a/src/expr.c b/src/expr.c
index f27bed5..1723e60 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.194 2005/02/12 08:59:57 danielk1977 Exp $
+** $Id: expr.c,v 1.195 2005/03/09 12:26:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -403,6 +403,7 @@
pNew->pRight = sqlite3ExprDup(p->pRight);
pNew->pList = sqlite3ExprListDup(p->pList);
pNew->pSelect = sqlite3SelectDup(p->pSelect);
+ pNew->pTab = p->pTab;
return pNew;
}
void sqlite3TokenCopy(Token *pTo, Token *pFrom){
@@ -847,6 +848,7 @@
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->affinity = pTab->aCol[j].affinity;
pExpr->pColl = pTab->aCol[j].pColl;
+ pExpr->pTab = pTab;
break;
}
}
@@ -958,6 +960,9 @@
if( cnt==1 ){
assert( pNC!=0 );
sqlite3AuthRead(pParse, pExpr, pNC->pSrcList);
+ if( pMatch && !pMatch->pSelect ){
+ pExpr->pTab = pMatch->pTab;
+ }
}
return cnt!=1;
}
@@ -1385,11 +1390,7 @@
sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg);
}else if( pExpr->iColumn>=0 ){
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
-#ifndef NDEBUG
- if( pExpr->span.z && pExpr->span.n>0 && pExpr->span.n<100 ){
- VdbeComment((v, "# %T", &pExpr->span));
- }
-#endif
+ sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
}else{
sqlite3VdbeAddOp(v, OP_Recno, pExpr->iTable, 0);
}
diff --git a/src/main.c b/src/main.c
index 5a3f26c..8e7ca89 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.281 2005/02/19 08:18:06 danielk1977 Exp $
+** $Id: main.c,v 1.282 2005/03/09 12:26:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -258,7 +258,7 @@
db->file_format = 1;
}
- if( db->file_format==2 ){
+ if( db->file_format==2 || db->file_format==3 ){
/* File format 2 is treated exactly as file format 1. New
** databases are created with file format 1.
*/
@@ -269,11 +269,13 @@
/*
** file_format==1 Version 3.0.0.
** file_format==2 Version 3.1.3.
+ ** file_format==3 Version 3.1.4.
**
** Version 3.0 can only use files with file_format==1. Version 3.1.3
** can read and write files with file_format==1 or file_format==2.
+ ** Version 3.1.4 can read and write file formats 1, 2 and 3.
*/
- if( meta[1]>2 ){
+ if( meta[1]>3 ){
sqlite3BtreeCloseCursor(curMain);
sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
return SQLITE_ERROR;
diff --git a/src/parse.y b/src/parse.y
index 2ad78de..f8b8979 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.166 2005/02/14 06:38:40 danielk1977 Exp $
+** @(#) $Id: parse.y,v 1.167 2005/03/09 12:26:51 danielk1977 Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -603,7 +603,7 @@
term(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
-expr(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
+term(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 8bc5a60..174c0d2 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.371 2005/02/15 21:36:18 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.372 2005/03/09 12:26:51 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -805,6 +805,10 @@
** be the right operand of an IN operator. Or, if a scalar SELECT appears
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
** operand.
+**
+** If the Expr is of type OP_Column, and the table it is selecting from
+** is a disk table or the "old.*" pseudo-table, then pTab points to the
+** corresponding table definition.
*/
struct Expr {
u8 op; /* Operation performed by this node */
@@ -824,6 +828,7 @@
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */
Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */
+ Table *pTab; /* Table for OP_Column expressions. */
};
/*
@@ -1536,6 +1541,8 @@
void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew();
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
+int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
+void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
extern const unsigned char sqlite3UpperToLower[];
void sqlite3RootPageMoved(Db*, int, int);
void sqlite3Reindex(Parse*, Token*, Token*);
@@ -1546,5 +1553,6 @@
void sqlite3ExpirePreparedStatements(sqlite3*);
void sqlite3CodeSubselect(Parse *, Expr *);
int sqlite3SelectResolve(Parse *, Select *, NameContext *);
+void sqlite3ColumnDefault(Vdbe *, Table *, int);
#endif
diff --git a/src/update.c b/src/update.c
index 81e5db9..5b52816 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,11 +12,46 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.104 2005/01/29 08:32:45 danielk1977 Exp $
+** $Id: update.c,v 1.105 2005/03/09 12:26:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
+** The most recently coded instruction was an OP_Column to retrieve column
+** 'i' of table pTab. This routine sets the P3 parameter of the
+** OP_Column to the default value, if any.
+**
+** The default value of a column is specified by a DEFAULT clause in the
+** column definition. This was either supplied by the user when the table
+** was created, or added later to the table definition by an ALTER TABLE
+** command. If the latter, then the row-records in the table btree on disk
+** may not contain a value for the column and the default value, taken
+** from the P3 parameter of the OP_Column instruction, is returned instead.
+** If the former, then all row-records are guaranteed to include a value
+** for the column and the P3 value is not required.
+**
+** Column definitions created by an ALTER TABLE command may only have
+** literal default values specified: a number, null or a string. (If a more
+** complicated default expression value was provided, it is evaluated
+** when the ALTER TABLE is executed and one of the literal values written
+** into the sqlite_master table.)
+**
+** Therefore, the P3 parameter is only required if the default value for
+** the column is a literal number, string or null. The sqlite3ValueFromExpr()
+** function is capable of transforming these types of expressions into
+** sqlite3_value objects.
+*/
+void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
+ if( pTab && !pTab->pSelect ){
+ sqlite3_value *pValue;
+ u8 enc = sqlite3VdbeDb(v)->enc;
+ Column *pCol = &pTab->aCol[i];
+ sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
+ sqlite3VdbeChangeP3(v, -1, (const char *)pValue, P3_MEM);
+ }
+}
+
+/*
** Process an UPDATE statement.
**
** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
@@ -294,6 +329,7 @@
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
+ sqlite3ColumnDefault(v, pTab, i);
}else{
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
}
@@ -378,6 +414,7 @@
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
+ sqlite3ColumnDefault(v, pTab, i);
}else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
}
diff --git a/src/vdbe.c b/src/vdbe.c
index 6b52ff7..cfb941a 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.456 2005/02/19 08:18:06 danielk1977 Exp $
+** $Id: vdbe.c,v 1.457 2005/03/09 12:26:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -303,6 +303,14 @@
}
}
+/*
+** Exported version of applyAffinity(). This one works on sqlite3_value*,
+** not the internal Mem* type.
+*/
+void sqlite3ValueApplyAffinity(sqlite3_value *pVal, u8 affinity, u8 enc){
+ applyAffinity((Mem *)pVal, affinity, enc);
+}
+
#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
@@ -1677,7 +1685,7 @@
break;
}
-/* Opcode: Column P1 P2 *
+/* Opcode: Column P1 P2 P3
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
@@ -1911,7 +1919,11 @@
sqlite3VdbeSerialGet(zData, aType[p2], pTos);
pTos->enc = db->enc;
}else{
- pTos->flags = MEM_Null;
+ if( pOp->p3 ){
+ sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static);
+ }else{
+ pTos->flags = MEM_Null;
+ }
}
/* If we dynamically allocated space to hold the data (in the
diff --git a/src/vdbe.h b/src/vdbe.h
index d0e9fb1..37882f2 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
-** $Id: vdbe.h,v 1.92 2005/01/29 08:32:45 danielk1977 Exp $
+** $Id: vdbe.h,v 1.93 2005/03/09 12:26:51 danielk1977 Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -69,6 +69,7 @@
#define P3_FUNCDEF (-5) /* P3 is a pointer to a FuncDef structure */
#define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */
#define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */
+#define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */
/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the
@@ -120,6 +121,7 @@
void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
+sqlite3 *sqlite3VdbeDb(Vdbe*);
#ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 6d77d72..e422add 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1420,6 +1420,9 @@
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqliteFree(pVdbeFunc);
}
+ if( pOp->p3type==P3_MEM ){
+ sqlite3ValueFree((sqlite3_value*)pOp->p3);
+ }
}
sqliteFree(p->aOp);
}
@@ -1847,3 +1850,10 @@
p->expired = 1;
}
}
+
+/*
+** Return the database associated with the Vdbe.
+*/
+sqlite3 *sqlite3VdbeDb(Vdbe *v){
+ return v->db;
+}
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 23da9ce..49b874e 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -701,6 +701,72 @@
}
/*
+** Create a new sqlite3_value object, containing the value of pExpr.
+**
+** This only works for very simple expressions that consist of one constant
+** token (i.e. "5", "5.1", "NULL", "'a string'"). If the expression can
+** be converted directly into a value, then the value is allocated and
+** a pointer written to *ppVal. The caller is responsible for deallocating
+** the value by passing it to sqlite3ValueFree() later on. If the expression
+** cannot be converted to a value, then *ppVal is set to NULL.
+*/
+int sqlite3ValueFromExpr(
+ Expr *pExpr,
+ u8 enc,
+ u8 affinity,
+ sqlite3_value **ppVal
+){
+ int op;
+ char *zVal = 0;
+ sqlite3_value *pVal = 0;
+
+ if( !pExpr ){
+ *ppVal = 0;
+ return SQLITE_OK;
+ }
+ op = pExpr->op;
+
+ if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
+ zVal = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
+ pVal = sqlite3ValueNew();
+ if( !zVal || !pVal ) goto no_mem;
+ sqlite3Dequote(zVal);
+ sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, sqlite3FreeX);
+ if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
+ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, enc);
+ }else{
+ sqlite3ValueApplyAffinity(pVal, affinity, enc);
+ }
+ }else if( op==TK_UMINUS ) {
+ if( SQLITE_OK==sqlite3ValueFromExpr(pExpr->pLeft, enc, affinity, &pVal) ){
+ pVal->i = -1 * pVal->i;
+ pVal->r = -1.0 * pVal->r;
+ }
+ }
+#ifndef SQLITE_OMIT_BLOB_LITERAL
+ else if( op==TK_BLOB ){
+ int nVal;
+ pVal = sqlite3ValueNew();
+ zVal = sqliteStrNDup(pExpr->token.z+1, pExpr->token.n-1);
+ if( !zVal || !pVal ) goto no_mem;
+ sqlite3Dequote(zVal);
+ nVal = strlen(zVal)/2;
+ sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(zVal), nVal, 0, sqlite3FreeX);
+ sqliteFree(zVal);
+ }
+#endif
+
+ *ppVal = pVal;
+ return SQLITE_OK;
+
+no_mem:
+ sqliteFree(zVal);
+ sqlite3ValueFree(pVal);
+ *ppVal = 0;
+ return SQLITE_NOMEM;
+}
+
+/*
** Change the string value of an sqlite3_value object
*/
void sqlite3ValueSetStr(