diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/alter.c | 179 | ||||
-rw-r--r-- | src/build.c | 4 | ||||
-rw-r--r-- | src/prepare.c | 26 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/trigger.c | 2 | ||||
-rw-r--r-- | src/vdbe.c | 2 | ||||
-rw-r--r-- | src/vdbe.h | 2 | ||||
-rw-r--r-- | src/vdbeaux.c | 3 | ||||
-rw-r--r-- | src/vtab.c | 2 |
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; |