aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alter.c179
-rw-r--r--src/build.c4
-rw-r--r--src/prepare.c26
-rw-r--r--src/sqliteInt.h3
-rw-r--r--src/trigger.c2
-rw-r--r--src/vdbe.c2
-rw-r--r--src/vdbe.h2
-rw-r--r--src/vdbeaux.c3
-rw-r--r--src/vtab.c2
9 files changed, 114 insertions, 109 deletions
diff --git a/src/alter.c b/src/alter.c
index 4b00d4c38..4fc2d1f7f 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -77,12 +77,12 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
** Generate code to reload the schema for database iDb. And, if iDb!=1, for
** the temp database as well.
*/
-static void renameReloadSchema(Parse *pParse, int iDb){
+static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
Vdbe *v = pParse->pVdbe;
if( v ){
sqlite3ChangeCookie(pParse, iDb);
- sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
- if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
+ sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
+ if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
}
}
@@ -250,7 +250,7 @@ void sqlite3AlterRenameTable(
}
#endif
- renameReloadSchema(pParse, iDb);
+ renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
renameTestSchema(pParse, zDb, iDb==1);
exit_rename_table:
@@ -413,7 +413,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
/* Reload the table definition */
- renameReloadSchema(pParse, iDb);
+ renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
}
/*
@@ -513,7 +513,7 @@ exit_begin_add_column:
** Or, if pTab is not a view or virtual table, zero is returned.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
-static int isRealTable(Parse *pParse, Table *pTab){
+static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
const char *zType = 0;
#ifndef SQLITE_OMIT_VIEW
if( pTab->pSelect ){
@@ -526,15 +526,16 @@ static int isRealTable(Parse *pParse, Table *pTab){
}
#endif
if( zType ){
- sqlite3ErrorMsg(
- pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName
+ sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"",
+ (bDrop ? "drop column from" : "rename columns of"),
+ zType, pTab->zName
);
return 1;
}
return 0;
}
#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
-# define isRealTable(x,y) (0)
+# define isRealTable(x,y,z) (0)
#endif
/*
@@ -563,7 +564,7 @@ void sqlite3AlterRenameColumn(
/* Cannot alter a system table */
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
- if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
+ if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column;
/* Which schema holds the table to be altered */
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -617,7 +618,7 @@ void sqlite3AlterRenameColumn(
);
/* Drop and reload the database schema. */
- renameReloadSchema(pParse, iSchema);
+ renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename);
renameTestSchema(pParse, zDb, iSchema==1);
exit_rename_column:
@@ -1762,12 +1763,17 @@ static void renameTableTest(
}
/*
+** The implementation of internal UDF sqlite_drop_column().
+**
** Arguments:
**
** argv[0]: An integer - the index of the schema containing the table
** argv[1]: CREATE TABLE statement to modify.
** argv[2]: An integer - the index of the column to remove.
** argv[3]: Byte offset of first byte after last column definition in argv[1]
+**
+** The value returned is a string containing the CREATE TABLE statement
+** with column argv[2] removed.
*/
static void dropColumnFunc(
sqlite3_context *context,
@@ -1809,21 +1815,21 @@ drop_column_done:
renameParseCleanup(&sParse);
}
+/*
+** This function is called by the parser upon parsing an
+**
+** ALTER TABLE pSrc DROP COLUMN pName
+**
+** statement. Argument pSrc contains the possibly qualified name of the
+** table being edited, and token pName the name of the column to drop.
+*/
void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
- Table *pTab;
- int i;
- int iSchema = 0;
- const char *zDb = 0;
- sqlite3 *db = pParse->db;
- char *zCol = 0;
- int iCol = 0;
- Vdbe *v;
- int iCur;
- int addr;
- int reg;
- int regRec;
- Index *pIdx;
- Index *pPk = 0;
+ sqlite3 *db = pParse->db; /* Database handle */
+ Table *pTab; /* Table to modify */
+ int iDb; /* Index of db containing pTab in aDb[] */
+ const char *zDb; /* Database containing pTab ("main" etc.) */
+ char *zCol = 0; /* Name of column to drop */
+ int iCol; /* Index of column zCol in pTab->aCol[] */
/* Look up the table being altered. */
assert( pParse->pNewTable==0 );
@@ -1832,26 +1838,10 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_drop_column;
- /* Which schema holds the table to be altered */
- iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
- assert( iSchema>=0 );
- zDb = db->aDb[iSchema].zDbSName;
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pTab) ){
- sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
- goto exit_drop_column;
- }
-#endif
-
- /* Make sure this is not an attempt to ALTER a view. */
- if( pTab->pSelect ){
- sqlite3ErrorMsg(pParse, "cannot drop a column from a view");
- goto exit_drop_column;
- }
- if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
- goto exit_drop_column;
- }
+ /* Make sure this is not an attempt to ALTER a view, virtual table or
+ ** system table. */
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column;
+ if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column;
/* Find the index of the column being dropped. */
zCol = sqlite3NameFromToken(db, pName);
@@ -1867,65 +1857,74 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
/* Do not allow the user to drop a PRIMARY KEY column or a column
** constrained by a UNIQUE constraint. */
- if( pTab->iPKey==iCol ){
- sqlite3ErrorMsg(pParse, "cannot drop PRIMARY KEY column: \"%s\"", zCol);
+ if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){
+ sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"",
+ (pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE",
+ zCol
+ );
goto exit_drop_column;
}
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int ii;
- for(ii=0; ii<pIdx->nKeyCol; ii++){
- if( iCol==pIdx->aiColumn[ii]
- && sqlite3_strnicmp("sqlite_", pIdx->zName, 7)==0
- ){
- sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"",
- pIdx->idxType==2 ? "PRIMARY KEY" : "UNIQUE", zCol
- );
- goto exit_drop_column;
- }
- }
- }
+ /* Edit the sqlite_schema table */
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iDb>=0 );
+ zDb = db->aDb[iDb].zDbSName;
sqlite3NestedParse(pParse,
"UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = sqlite_drop_column(%d, sql, %d, %d) "
"WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)"
- , zDb, iSchema, iCol, pTab->addColOffset, pTab->zName
+ , zDb, iDb, iCol, pTab->addColOffset, pTab->zName
);
/* Drop and reload the database schema. */
- renameReloadSchema(pParse, iSchema);
- renameTestSchema(pParse, zDb, iSchema==1);
+ renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop);
+ renameTestSchema(pParse, zDb, iDb==1);
/* Edit rows of table on disk */
- v = sqlite3GetVdbe(pParse);
- iCur = pParse->nTab++;
- sqlite3OpenTable(pParse, iCur, iSchema, pTab, OP_OpenWrite);
- addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur);
- reg = ++pParse->nMem;
- pParse->nMem += pTab->nCol;
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
- }else{
- pPk = sqlite3PrimaryKeyIndex(pTab);
- }
- for(i=0; i<pTab->nCol; i++){
- if( i!=iCol ){
- int iPos = (pPk ? sqlite3TableColumnToIndex(pPk, i) : i);
- int iColPos = (pPk ? sqlite3TableColumnToIndex(pPk, iCol) : iCol);
- int regOut = reg+1+iPos-(iPos>iColPos);
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
+ if( (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){
+ int i;
+ int addr;
+ int reg;
+ int regRec;
+ Index *pPk = 0;
+ int nField = 0; /* Number of non-virtual columns after drop */
+ int iCur;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ iCur = pParse->nTab++;
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
+ addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur);
+ reg = ++pParse->nMem;
+ pParse->nMem += pTab->nCol;
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
+ }else{
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ }
+ for(i=0; i<pTab->nCol; i++){
+ if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ int regOut;
+ if( pPk ){
+ int iPos = sqlite3TableColumnToIndex(pPk, i);
+ int iColPos = sqlite3TableColumnToIndex(pPk, iCol);
+ regOut = reg+1+iPos-(iPos>iColPos);
+ }else{
+ regOut = reg+1+nField;
+ }
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
+ nField++;
+ }
+ }
+ regRec = reg + pTab->nCol;
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec);
+ if( pPk ){
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
}
- }
- regRec = reg + pTab->nCol;
- sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, pTab->nCol-1, regRec);
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
- }else{
- sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
- }
- sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1);
- sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1);
+ sqlite3VdbeJumpHere(v, addr);
+ }
exit_drop_column:
sqlite3DbFree(db, zCol);
diff --git a/src/build.c b/src/build.c
index f5c796fac..065b50c08 100644
--- a/src/build.c
+++ b/src/build.c
@@ -2638,7 +2638,7 @@ void sqlite3EndTable(
/* Reparse everything to update our internal data structures */
sqlite3VdbeAddParseSchemaOp(v, iDb,
- sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
+ sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
}
/* Add the table to the in-memory representation of the database.
@@ -4126,7 +4126,7 @@ void sqlite3CreateIndex(
sqlite3RefillIndex(pParse, pIndex, iMem);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb,
- sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
+ sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
}
diff --git a/src/prepare.c b/src/prepare.c
index 87c1ab936..4888744a8 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -21,7 +21,7 @@
*/
static void corruptSchema(
InitData *pData, /* Initialization context */
- const char *zObj, /* Object being parsed at the point of error */
+ char **azObj, /* Type and name of object being parsed */
const char *zExtra /* Error information */
){
sqlite3 *db = pData->db;
@@ -29,14 +29,18 @@ static void corruptSchema(
pData->rc = SQLITE_NOMEM_BKPT;
}else if( pData->pzErrMsg[0]!=0 ){
/* A error message has already been generated. Do not overwrite it */
- }else if( pData->mInitFlags & INITFLAG_AlterTable ){
- *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
+ }else if( pData->mInitFlags & (INITFLAG_AlterRename|INITFLAG_AlterDrop) ){
+ *pData->pzErrMsg = sqlite3MPrintf(db,
+ "error in %s %s after %s: %s", azObj[0], azObj[1],
+ (pData->mInitFlags & INITFLAG_AlterRename) ? "rename" : "drop column",
+ zExtra
+ );
pData->rc = SQLITE_ERROR;
}else if( db->flags & SQLITE_WriteSchema ){
pData->rc = SQLITE_CORRUPT_BKPT;
}else{
char *z;
- if( zObj==0 ) zObj = "?";
+ const char *zObj = azObj[1] ? azObj[1] : "?";
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
*pData->pzErrMsg = z;
@@ -94,14 +98,14 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
db->mDbFlags |= DBFLAG_EncodingFixed;
pData->nInitRow++;
if( db->mallocFailed ){
- corruptSchema(pData, argv[1], 0);
+ corruptSchema(pData, argv, 0);
return 1;
}
assert( iDb>=0 && iDb<db->nDb );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[3]==0 ){
- corruptSchema(pData, argv[1], 0);
+ corruptSchema(pData, argv, 0);
}else if( argv[4]
&& 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]]
&& 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){
@@ -126,7 +130,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|| (db->init.newTnum>pData->mxPage && pData->mxPage>0)
){
if( sqlite3Config.bExtraSchemaChecks ){
- corruptSchema(pData, argv[1], "invalid rootpage");
+ corruptSchema(pData, argv, "invalid rootpage");
}
}
db->init.orphanTrigger = 0;
@@ -145,13 +149,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
- corruptSchema(pData, argv[1], sqlite3_errmsg(db));
+ corruptSchema(pData, argv, sqlite3_errmsg(db));
}
}
}
sqlite3_finalize(pStmt);
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
- corruptSchema(pData, argv[1], 0);
+ corruptSchema(pData, argv, 0);
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -162,7 +166,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
Index *pIndex;
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
if( pIndex==0 ){
- corruptSchema(pData, argv[1], "orphan index");
+ corruptSchema(pData, argv, "orphan index");
}else
if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
|| pIndex->tnum<2
@@ -170,7 +174,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|| sqlite3IndexHasDuplicateRootPage(pIndex)
){
if( sqlite3Config.bExtraSchemaChecks ){
- corruptSchema(pData, argv[1], "invalid rootpage");
+ corruptSchema(pData, argv, "invalid rootpage");
}
}
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 9c09b24ac..850396ced 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3711,7 +3711,8 @@ typedef struct {
/*
** Allowed values for mInitFlags
*/
-#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */
+#define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */
+#define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */
/*
** Structure containing global configuration data for the SQLite library.
diff --git a/src/trigger.c b/src/trigger.c
index 1d4c2790c..689c7c741 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -356,7 +356,7 @@ void sqlite3FinishTrigger(
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb,
- sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
+ sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
}
if( db->init.busy ){
diff --git a/src/vdbe.c b/src/vdbe.c
index 97cd696de..153ed40b7 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -6330,7 +6330,7 @@ case OP_ParseSchema: {
if( pOp->p4.z==0 ){
sqlite3SchemaClear(db->aDb[iDb].pSchema);
db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
- rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
+ rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5);
db->mDbFlags |= DBFLAG_SchemaChange;
p->expired = 0;
}else
diff --git a/src/vdbe.h b/src/vdbe.h
index 17f11fdd7..3257ff68a 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -223,7 +223,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#else
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
-void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
+void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 7ee4f629e..ede652dfa 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -471,9 +471,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
** The zWhere string must have been obtained from sqlite3_malloc().
** This routine will take ownership of the allocated memory.
*/
-void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
+void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){
int j;
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
+ sqlite3VdbeChangeP5(p, p5);
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
sqlite3MayAbort(p->pParse);
}
diff --git a/src/vtab.c b/src/vtab.c
index 400ae4096..0da5518b1 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -489,7 +489,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp0(v, OP_Expire);
zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
- sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
+ sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
sqlite3DbFree(db, zStmt);
iReg = ++pParse->nMem;