aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alter.c180
-rw-r--r--src/build.c13
-rw-r--r--src/parse.y4
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/tokenize.c4
-rw-r--r--src/trigger.c38
6 files changed, 166 insertions, 75 deletions
diff --git a/src/alter.c b/src/alter.c
index a07c248b3..89be503fc 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -817,13 +817,6 @@ void sqlite3AlterRenameColumn(
/* Cannot alter a system table */
if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
- /* Cannot rename columns of a virtual table */
- if( IsVirtual(pTab) ){
- sqlite3ErrorMsg(pParse, "cannot rename columns in a virtual table (%s)",
- pTab->zName);
- goto exit_rename_column;
- }
-
/* Which schema holds the table to be altered */
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iSchema>=0 );
@@ -851,11 +844,14 @@ void sqlite3AlterRenameColumn(
bQuote = sqlite3Isquote(pNew->z[0]);
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
- "sql = sqlite_rename_column(sql, %d, %d, %Q, %Q, %Q) "
+ "sql = sqlite_rename_column(sql, %Q, %Q, %d, %Q, %d) "
"WHERE name NOT LIKE 'sqlite_%%' AND ("
- " type = 'table' OR (type='index' AND tbl_name = %Q)"
+ " type IN ('table', 'view') "
+ " OR (type IN ('index', 'trigger') AND tbl_name = %Q)"
")",
- zDb, MASTER_NAME, iCol, bQuote, zNew, pTab->zName, zOld, pTab->zName
+ zDb, MASTER_NAME,
+ zDb, pTab->zName, iCol, zNew, bQuote,
+ pTab->zName
);
/* Drop and reload the database schema. */
@@ -898,10 +894,13 @@ struct RenameToken {
** The context of an ALTER TABLE RENAME COLUMN operation that gets passed
** down into the Walker.
*/
+typedef struct RenameCtx RenameCtx;
struct RenameCtx {
RenameToken *pList; /* List of tokens to overwrite */
int nList; /* Number of tokens in pList */
int iCol; /* Index of column being renamed */
+ Table *pTab; /* Table being ALTERed */
+ const char *zOld; /* Old column name */
};
/*
@@ -967,6 +966,10 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
}
}
+static int renameColumnSelectCb(Walker *pWalker, Select *p){
+ return WRC_Continue;
+}
+
/*
** This is a Walker expression callback.
@@ -978,8 +981,21 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
** constructed in RenameCtx object at pWalker->u.pRename.
*/
static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
- struct RenameCtx *p = pWalker->u.pRename;
- if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol ){
+ RenameCtx *p = pWalker->u.pRename;
+ if( p->zOld && pExpr->op==TK_DOT ){
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ assert( pLeft->op==TK_ID && pRight->op==TK_ID );
+ if( 0==sqlite3_stricmp(pLeft->u.zToken, "old")
+ || 0==sqlite3_stricmp(pLeft->u.zToken, "new")
+ ){
+ if( 0==sqlite3_stricmp(pRight->u.zToken, p->zOld) ){
+ renameTokenFind(pWalker->pParse, p, (void*)pRight);
+ }
+ }
+ }else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol
+ && (p->pTab==0 || p->pTab==pExpr->pTab)
+ ){
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
}
return WRC_Continue;
@@ -994,7 +1010,7 @@ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
** return all column name tokens in the order that they are encountered
** in the SQL statement.
*/
-static RenameToken *renameColumnTokenNext(struct RenameCtx *pCtx){
+static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
RenameToken *pBest = pCtx->pList;
RenameToken *pToken;
RenameToken **pp;
@@ -1013,6 +1029,13 @@ static RenameToken *renameColumnTokenNext(struct RenameCtx *pCtx){
**
** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
**
+** 0. zSql: SQL statement to rewrite
+** 1. Database: Database name (e.g. "main")
+** 2. Table: Table name
+** 3. iCol: Index of column to rename
+** 4. zNew: New column name
+** 5. bQuote: True if the new column name should be quoted
+**
** Do a column rename operation on the CREATE statement given in zSql.
** The iCol-th column (left-most is 0) of table zTable is renamed from zCol
** into zNew. The name should be quoted if bQuote is true.
@@ -1034,14 +1057,16 @@ static void renameColumnFunc(
sqlite3_value **argv
){
sqlite3 *db = sqlite3_context_db_handle(context);
- struct RenameCtx sCtx;
+ RenameCtx sCtx;
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
int nSql = sqlite3_value_bytes(argv[0]);
- int bQuote = sqlite3_value_int(argv[2]);
- const char *zNew = (const char*)sqlite3_value_text(argv[3]);
- int nNew = sqlite3_value_bytes(argv[3]);
- const char *zTable = (const char*)sqlite3_value_text(argv[4]);
- const char *zOld = (const char*)sqlite3_value_text(argv[5]);
+ const char *zDb = (const char*)sqlite3_value_text(argv[1]);
+ const char *zTable = (const char*)sqlite3_value_text(argv[2]);
+ int iCol = sqlite3_value_int(argv[3]);
+ const char *zNew = (const char*)sqlite3_value_text(argv[4]);
+ int nNew = sqlite3_value_bytes(argv[4]);
+ int bQuote = sqlite3_value_int(argv[5]);
+ const char *zOld;
int rc;
char *zErr = 0;
@@ -1053,14 +1078,17 @@ static void renameColumnFunc(
char *zQuot = 0; /* Quoted version of zNew */
int nQuot = 0; /* Length of zQuot in bytes */
int i;
+ Table *pTab;
if( zSql==0 ) return;
if( zNew==0 ) return;
if( zTable==0 ) return;
- if( zOld==0 ) return;
+ if( iCol<0 ) return;
+ pTab = sqlite3FindTable(db, zTable, zDb);
+ if( pTab==0 || iCol>=pTab->nCol ) return;
+ zOld = pTab->aCol[iCol].zName;
memset(&sCtx, 0, sizeof(sCtx));
- sCtx.iCol = sqlite3_value_int(argv[1]);
- if( sCtx.iCol<0 ) return;
+ sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
memset(&sParse, 0, sizeof(sParse));
sParse.eParseMode = PARSE_MODE_RENAME_COLUMN;
@@ -1069,7 +1097,9 @@ static void renameColumnFunc(
rc = sqlite3RunParser(&sParse, zSql, &zErr);
assert( sParse.pNewTable==0 || sParse.pNewIndex==0 );
if( db->mallocFailed ) rc = SQLITE_NOMEM;
- if( rc==SQLITE_OK && sParse.pNewTable==0 && sParse.pNewIndex==0 ){
+ if( rc==SQLITE_OK
+ && sParse.pNewTable==0 && sParse.pNewIndex==0 && sParse.pNewTrigger==0
+ ){
rc = SQLITE_CORRUPT_BKPT;
}
@@ -1082,16 +1112,6 @@ static void renameColumnFunc(
}
}
- if( rc!=SQLITE_OK ){
- if( zErr ){
- sqlite3_result_error(context, zErr, -1);
- }else{
- sqlite3_result_error_code(context, rc);
- }
- sqlite3DbFree(db, zErr);
- goto renameColumnFunc_done;
- }
-
if( bQuote ){
zNew = zQuot;
nNew = nQuot;
@@ -1099,7 +1119,7 @@ static void renameColumnFunc(
#ifdef SQLITE_DEBUG
assert( sqlite3Strlen30(zSql)==nSql );
- {
+ if( rc==SQLITE_OK ){
RenameToken *pToken;
for(pToken=sParse.pRename; pToken; pToken=pToken->pNext){
assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
@@ -1111,42 +1131,75 @@ static void renameColumnFunc(
memset(&sWalker, 0, sizeof(Walker));
sWalker.pParse = &sParse;
sWalker.xExprCallback = renameColumnExprCb;
+ sWalker.xSelectCallback = renameColumnSelectCb;
sWalker.u.pRename = &sCtx;
+ if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
if( sParse.pNewTable ){
- int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
- FKey *pFKey;
- for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
- for(i=0; i<pFKey->nCol; i++){
- if( bFKOnly==0 && pFKey->aCol[i].iFrom==sCtx.iCol ){
- renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
+ Select *pSelect = sParse.pNewTable->pSelect;
+ if( pSelect ){
+ sCtx.pTab = pTab;
+ sParse.rc = SQLITE_OK;
+ sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0);
+ rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
+ if( rc==SQLITE_OK ){
+ sqlite3WalkSelect(&sWalker, pSelect);
+ }else if( rc==SQLITE_ERROR ){
+ /* Failed to resolve all symboles in the view. This is not an
+ ** error, but it will not be edited. */
+ sqlite3DbFree(db, sParse.zErrMsg);
+ sParse.zErrMsg = 0;
+ rc = SQLITE_OK;
+ }
+ if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+ }else{
+ /* A regular table */
+ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
+ FKey *pFKey;
+ assert( sParse.pNewTable->pSelect==0 );
+ if( bFKOnly==0 ){
+ renameTokenFind(
+ &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName
+ );
+ if( sCtx.iCol<0 ){
+ renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
}
- if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
- && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
- ){
- renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
+ sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
+ for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
+ sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
}
}
- }
- if( bFKOnly==0 ){
- renameTokenFind(
- &sParse, &sCtx, (void*)sParse.pNewTable->aCol[sCtx.iCol].zName
- );
- assert( sCtx.iCol>=0 );
- if( sParse.pNewTable->iPKey==sCtx.iCol ){
- renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
- sCtx.iCol = -1;
- }
- sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
- for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
+
+ for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+ for(i=0; i<pFKey->nCol; i++){
+ if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){
+ renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
+ }
+ if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
+ && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
+ ){
+ renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
+ }
+ }
}
}
- }else{
+ }else if( sParse.pNewIndex ){
sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
+ }else{
+ sCtx.zOld = zOld;
+ sqlite3WalkExpr(&sWalker, sParse.pNewTrigger->pWhen);
+ if( sParse.pNewTrigger->pColumns ){
+ for(i=0; i<sParse.pNewTrigger->pColumns->nId; i++){
+ char *zName = sParse.pNewTrigger->pColumns->a[i].zName;
+ if( 0==sqlite3_stricmp(zName, zOld) ){
+ renameTokenFind(&sParse, &sCtx, (void*)zName);
+ }
+ }
+ }
}
+ assert( rc==SQLITE_OK );
assert( nQuot>=nNew );
zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nQuot + 1);
if( zOut ){
@@ -1180,14 +1233,25 @@ static void renameColumnFunc(
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
sqlite3DbFree(db, zOut);
+ }else{
+ rc = SQLITE_NOMEM;
}
renameColumnFunc_done:
+ if( rc!=SQLITE_OK ){
+ if( zErr ){
+ sqlite3_result_error(context, zErr, -1);
+ }else{
+ sqlite3_result_error_code(context, rc);
+ }
+ }
+
if( sParse.pVdbe ){
sqlite3VdbeFinalize(sParse.pVdbe);
}
sqlite3DeleteTable(db, sParse.pNewTable);
if( sParse.pNewIndex ) sqlite3FreeIndex(db, sParse.pNewIndex);
+ sqlite3DeleteTrigger(db, sParse.pNewTrigger);
renameTokenFree(db, sParse.pRename);
renameTokenFree(db, sCtx.pList);
sqlite3ParserReset(&sParse);
diff --git a/src/build.c b/src/build.c
index 31ef2e17d..68fecd103 100644
--- a/src/build.c
+++ b/src/build.c
@@ -2175,7 +2175,12 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
- p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+ if( IN_RENAME_COLUMN ){
+ p->pSelect = pSelect;
+ pSelect = 0;
+ }else{
+ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+ }
p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
if( db->mallocFailed ) goto create_view_fail;
@@ -3689,7 +3694,8 @@ void *sqlite3ArrayAllocate(
**
** A new IdList is returned, or NULL if malloc() fails.
*/
-IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
+IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
+ sqlite3 *db = pParse->db;
int i;
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
@@ -3707,6 +3713,9 @@ IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
return 0;
}
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
+ if( IN_RENAME_COLUMN && pList->a[i].zName ){
+ sqlite3RenameToken(pParse, (void*)pList->a[i].zName, pToken);
+ }
return pList;
}
diff --git a/src/parse.y b/src/parse.y
index 47e73feb8..76e966a4d 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -908,9 +908,9 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
idlist_opt(A) ::= . {A = 0;}
idlist_opt(A) ::= LP idlist(X) RP. {A = X;}
idlist(A) ::= idlist(A) COMMA nm(Y).
- {A = sqlite3IdListAppend(pParse->db,A,&Y);}
+ {A = sqlite3IdListAppend(pParse,A,&Y);}
idlist(A) ::= nm(Y).
- {A = sqlite3IdListAppend(pParse->db,0,&Y); /*A-overwrites-Y*/}
+ {A = sqlite3IdListAppend(pParse,0,&Y); /*A-overwrites-Y*/}
/////////////////////////// Expression Processing /////////////////////////////
//
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e7d86ba3b..f2e6121de 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3887,7 +3887,7 @@ void sqlite3FreeIndex(sqlite3*, Index*);
#endif
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*);
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
-IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
+IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
diff --git a/src/tokenize.c b/src/tokenize.c
index 685d10b25..02d21f1f5 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -697,9 +697,11 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
+ if( !IN_RENAME_COLUMN ){
+ sqlite3DeleteTrigger(db, pParse->pNewTrigger);
+ }
if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
- sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->pVList);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
diff --git a/src/trigger.c b/src/trigger.c
index 044f256ae..1df88fd80 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -181,14 +181,16 @@ void sqlite3BeginTrigger(
goto trigger_cleanup;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
- if( !noErr ){
- sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
- }else{
- assert( !db->init.busy );
- sqlite3CodeVerifySchema(pParse, iDb);
+ if( !IN_RENAME_COLUMN ){
+ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+ }else{
+ assert( !db->init.busy );
+ sqlite3CodeVerifySchema(pParse, iDb);
+ }
+ goto trigger_cleanup;
}
- goto trigger_cleanup;
}
/* Do not create a trigger on a system table */
@@ -212,7 +214,7 @@ void sqlite3BeginTrigger(
}
#ifndef SQLITE_OMIT_AUTHORIZATION
- {
+ if( !IN_RENAME_COLUMN ){
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[iTabDb].zDbSName;
@@ -246,8 +248,14 @@ void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
- pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
- pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
+ if( IN_RENAME_COLUMN ){
+ pTrigger->pWhen = pWhen;
+ pWhen = 0;
+ }else{
+ pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
+ }
+ pTrigger->pColumns = pColumns;
+ pColumns = 0;
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
@@ -296,6 +304,14 @@ void sqlite3FinishTrigger(
goto triggerfinish_cleanup;
}
+#ifndef SQLITE_OMIT_ALTERTABLE
+ if( IN_RENAME_COLUMN ){
+ assert( !db->init.busy );
+ pParse->pNewTrigger = pTrig;
+ pTrig = 0;
+ }else
+#endif
+
/* if we are not initializing,
** build the sqlite_master entry
*/
@@ -337,7 +353,7 @@ void sqlite3FinishTrigger(
triggerfinish_cleanup:
sqlite3DeleteTrigger(db, pTrig);
- assert( !pParse->pNewTrigger );
+ assert( IN_RENAME_COLUMN || !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(db, pStepList);
}