aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alter.c868
-rw-r--r--src/build.c34
-rw-r--r--src/expr.c2
-rw-r--r--src/parse.y32
-rw-r--r--src/prepare.c2
-rw-r--r--src/resolve.c21
-rw-r--r--src/sqliteInt.h5
-rw-r--r--src/tokenize.c2
-rw-r--r--src/trigger.c29
9 files changed, 513 insertions, 482 deletions
diff --git a/src/alter.c b/src/alter.c
index 50690b981..65880752c 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -20,211 +20,6 @@
*/
#ifndef SQLITE_OMIT_ALTERTABLE
-
-/*
-** This function is used by SQL generated to implement the
-** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
-** CREATE INDEX command. The second is a table name. The table name in
-** the CREATE TABLE or CREATE INDEX statement is replaced with the third
-** argument and the result returned. Examples:
-**
-** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
-** -> 'CREATE TABLE def(a, b, c)'
-**
-** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
-** -> 'CREATE INDEX i ON def(a, b, c)'
-*/
-static void renameTableFunc(
- sqlite3_context *context,
- int NotUsed,
- sqlite3_value **argv
-){
- unsigned char const *zSql = sqlite3_value_text(argv[0]);
- unsigned char const *zTableName = sqlite3_value_text(argv[1]);
-
- int token;
- Token tname;
- unsigned char const *zCsr = zSql;
- int len = 0;
- char *zRet;
-
- sqlite3 *db = sqlite3_context_db_handle(context);
-
- UNUSED_PARAMETER(NotUsed);
-
- /* The principle used to locate the table name in the CREATE TABLE
- ** statement is that the table name is the first non-space token that
- ** is immediately followed by a TK_LP or TK_USING token.
- */
- if( zSql ){
- do {
- if( !*zCsr ){
- /* Ran out of input before finding an opening bracket. Return NULL. */
- return;
- }
-
- /* Store the token that zCsr points to in tname. */
- tname.z = (char*)zCsr;
- tname.n = len;
-
- /* Advance zCsr to the next token. Store that token type in 'token',
- ** and its length in 'len' (to be used next iteration of this loop).
- */
- do {
- zCsr += len;
- len = sqlite3GetToken(zCsr, &token);
- } while( token==TK_SPACE );
- assert( len>0 || !*zCsr );
- } while( token!=TK_LP && token!=TK_USING );
-
- zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql),
- zSql, zTableName, tname.z+tname.n);
- sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
- }
-}
-
-/*
-** This C function implements an SQL user function that is used by SQL code
-** generated by the ALTER TABLE ... RENAME command to modify the definition
-** of any foreign key constraints that use the table being renamed as the
-** parent table. It is passed three arguments:
-**
-** 1) The complete text of the CREATE TABLE statement being modified,
-** 2) The old name of the table being renamed, and
-** 3) The new name of the table being renamed.
-**
-** It returns the new CREATE TABLE statement. For example:
-**
-** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3')
-** -> 'CREATE TABLE t1(a REFERENCES t3)'
-*/
-#ifndef SQLITE_OMIT_FOREIGN_KEY
-static void renameParentFunc(
- sqlite3_context *context,
- int NotUsed,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_context_db_handle(context);
- char *zOutput = 0;
- char *zResult;
- unsigned char const *zInput = sqlite3_value_text(argv[0]);
- unsigned char const *zOld = sqlite3_value_text(argv[1]);
- unsigned char const *zNew = sqlite3_value_text(argv[2]);
-
- unsigned const char *z; /* Pointer to token */
- int n; /* Length of token z */
- int token; /* Type of token */
-
- UNUSED_PARAMETER(NotUsed);
- if( zInput==0 || zOld==0 ) return;
- for(z=zInput; *z; z=z+n){
- n = sqlite3GetToken(z, &token);
- if( token==TK_REFERENCES ){
- char *zParent;
- do {
- z += n;
- n = sqlite3GetToken(z, &token);
- }while( token==TK_SPACE );
-
- if( token==TK_ILLEGAL ) break;
- zParent = sqlite3DbStrNDup(db, (const char *)z, n);
- if( zParent==0 ) break;
- sqlite3Dequote(zParent);
- if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){
- char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"",
- (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew
- );
- sqlite3DbFree(db, zOutput);
- zOutput = zOut;
- zInput = &z[n];
- }
- sqlite3DbFree(db, zParent);
- }
- }
-
- zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput);
- sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC);
- sqlite3DbFree(db, zOutput);
-}
-#endif
-
-#ifndef SQLITE_OMIT_TRIGGER
-/* This function is used by SQL generated to implement the
-** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
-** statement. The second is a table name. The table name in the CREATE
-** TRIGGER statement is replaced with the third argument and the result
-** returned. This is analagous to renameTableFunc() above, except for CREATE
-** TRIGGER, not CREATE INDEX and CREATE TABLE.
-*/
-static void renameTriggerFunc(
- sqlite3_context *context,
- int NotUsed,
- sqlite3_value **argv
-){
- unsigned char const *zSql = sqlite3_value_text(argv[0]);
- unsigned char const *zTableName = sqlite3_value_text(argv[1]);
-
- int token;
- Token tname;
- int dist = 3;
- unsigned char const *zCsr = zSql;
- int len = 0;
- char *zRet;
- sqlite3 *db = sqlite3_context_db_handle(context);
-
- UNUSED_PARAMETER(NotUsed);
-
- /* The principle used to locate the table name in the CREATE TRIGGER
- ** statement is that the table name is the first token that is immediately
- ** preceded by either TK_ON or TK_DOT and immediately followed by one
- ** of TK_WHEN, TK_BEGIN or TK_FOR.
- */
- if( zSql ){
- do {
-
- if( !*zCsr ){
- /* Ran out of input before finding the table name. Return NULL. */
- return;
- }
-
- /* Store the token that zCsr points to in tname. */
- tname.z = (char*)zCsr;
- tname.n = len;
-
- /* Advance zCsr to the next token. Store that token type in 'token',
- ** and its length in 'len' (to be used next iteration of this loop).
- */
- do {
- zCsr += len;
- len = sqlite3GetToken(zCsr, &token);
- }while( token==TK_SPACE );
- assert( len>0 || !*zCsr );
-
- /* Variable 'dist' stores the number of tokens read since the most
- ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
- ** token is read and 'dist' equals 2, the condition stated above
- ** to be met.
- **
- ** Note that ON cannot be a database, table or column name, so
- ** there is no need to worry about syntax like
- ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
- */
- dist++;
- if( token==TK_DOT || token==TK_ON ){
- dist = 0;
- }
- } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) );
-
- /* Variable tname now contains the token that is the old table-name
- ** in the CREATE TRIGGER statement.
- */
- zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql),
- zSql, zTableName, tname.z+tname.n);
- sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
- }
-}
-#endif /* !SQLITE_OMIT_TRIGGER */
-
/*
** This function is used to create the text of expressions of the form:
**
@@ -383,9 +178,6 @@ void sqlite3AlterRenameTable(
int nTabName; /* Number of UTF-8 characters in zTabName */
const char *zTabName; /* Original name of the table */
Vdbe *v;
-#ifndef SQLITE_OMIT_TRIGGER
- char *zWhere = 0; /* Where clause to locate temp triggers */
-#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
u32 savedDbFlags; /* Saved value of db->mDbFlags */
@@ -479,31 +271,20 @@ void sqlite3AlterRenameTable(
zTabName = pTab->zName;
nTabName = sqlite3Utf8CharLen(zTabName, -1);
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- if( db->flags&SQLITE_ForeignKeys ){
- /* If foreign-key support is enabled, rewrite the CREATE TABLE
- ** statements corresponding to all child tables of foreign key constraints
- ** for which the renamed table is the parent table. */
- if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
- sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
- "sql = sqlite_rename_parent(sql, %Q, %Q) "
- "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere);
- sqlite3DbFree(db, zWhere);
- }
- }
-#endif
+ /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
+ ** the schema to use the new table name. */
+ sqlite3NestedParse(pParse,
+ "UPDATE \"%w\".%s SET "
+ "sql = sqlite_rename_table(%Q, sql, %Q, %Q, 0) "
+ "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
+ "AND name NOT LIKE 'sqlite_%%'"
+ , zDb, MASTER_NAME, zDb, zTabName, zName, zTabName
+ );
- /* Modify the sqlite_master table to use the new table name. */
+ /* Update the tbl_name and name columns of the sqlite_master table
+ ** as required. */
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET "
-#ifdef SQLITE_OMIT_TRIGGER
- "sql = sqlite_rename_table(sql, %Q), "
-#else
- "sql = CASE "
- "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)"
- "ELSE sqlite_rename_table(sql, %Q) END, "
-#endif
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
@@ -512,11 +293,9 @@ void sqlite3AlterRenameTable(
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
- zDb, MASTER_NAME, zName, zName, zName,
-#ifndef SQLITE_OMIT_TRIGGER
- zName,
-#endif
- zName, nTabName, zTabName
+ zDb, MASTER_NAME,
+ zName, zName, zName,
+ nTabName, zTabName
);
#ifndef SQLITE_OMIT_AUTOINCREMENT
@@ -530,35 +309,21 @@ void sqlite3AlterRenameTable(
}
#endif
-#ifndef SQLITE_OMIT_TRIGGER
- /* If there are TEMP triggers on this table, modify the sqlite_temp_master
- ** table. Don't do this if the table being ALTERed is itself located in
- ** the temp database.
- */
- if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
+ /* If the table being renamed is not itself part of the temp database,
+ ** edit view and trigger definitions within the temp database
+ ** as required. */
+ if( iDb!=1 ){
sqlite3NestedParse(pParse,
"UPDATE sqlite_temp_master SET "
- "sql = sqlite_rename_trigger(sql, %Q), "
- "tbl_name = %Q "
- "WHERE %s;", zName, zName, zWhere);
- sqlite3DbFree(db, zWhere);
- }
-#endif
-
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- if( db->flags&SQLITE_ForeignKeys ){
- FKey *p;
- for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
- Table *pFrom = p->pFrom;
- if( pFrom!=pTab ){
- reloadTableSchema(pParse, p->pFrom, pFrom->zName);
- }
- }
+ "sql = sqlite_rename_table(%Q, sql, %Q, %Q, 1), "
+ "tbl_name = "
+ "CASE WHEN tbl_name=%Q COLLATE nocase THEN %Q ELSE tbl_name END "
+ "WHERE type IN ('view', 'trigger')"
+ , zDb, zTabName, zName, zTabName, zTabName, zName);
}
-#endif
- /* Drop and reload the internal table schema. */
- reloadTableSchema(pParse, pTab, zName);
+ sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
+ if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
@@ -946,6 +711,16 @@ struct RenameCtx {
const char *zOld; /* Old column name */
};
+void renameTokenClear(Parse *pParse, void *pPtr){
+ RenameToken *p;
+ assert( pPtr );
+ for(p=pParse->pRename; p; p=p->pNext){
+ if( p->p==pPtr ){
+ p->p = 0;
+ }
+ }
+}
+
/*
** Add a new RenameToken object mapping parse tree element pPtr into
** token *pToken to the Parse object currently under construction.
@@ -954,6 +729,9 @@ struct RenameCtx {
*/
void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
RenameToken *pNew;
+ assert( pPtr || pParse->db->mallocFailed );
+
+ renameTokenClear(pParse, pPtr);
pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
if( pNew ){
pNew->p = pPtr;
@@ -961,6 +739,7 @@ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
pNew->pNext = pParse->pRename;
pParse->pRename = pNew;
}
+
return pPtr;
}
@@ -971,13 +750,13 @@ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
*/
void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){
RenameToken *p;
- for(p=pParse->pRename; ALWAYS(p); p=p->pNext){
+ if( pTo ) renameTokenClear(pParse, pTo);
+ for(p=pParse->pRename; p; p=p->pNext){
if( p->p==pFrom ){
p->p = pTo;
break;
}
}
- assert( pTo==0 || p );
}
/*
@@ -1143,6 +922,221 @@ static void renameColumnIdlistNames(
}
}
+static int renameParseSql(
+ Parse *p,
+ const char *zDb,
+ int bTable,
+ sqlite3 *db,
+ const char *zSql,
+ int bTemp
+){
+ int rc;
+ char *zErr = 0;
+
+ db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
+
+ /* Parse the SQL statement passed as the first argument. If no error
+ ** occurs and the parse does not result in a new table, index or
+ ** trigger object, the database must be corrupt. */
+ memset(p, 0, sizeof(Parse));
+ p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN);
+ p->db = db;
+ p->nQueryLoop = 1;
+ rc = sqlite3RunParser(p, zSql, &zErr);
+ assert( p->zErrMsg==0 );
+ assert( rc!=SQLITE_OK || zErr==0 );
+ assert( (0!=p->pNewTable) + (0!=p->pNewIndex) + (0!=p->pNewTrigger)<2 );
+ p->zErrMsg = zErr;
+ if( db->mallocFailed ) rc = SQLITE_NOMEM;
+ if( rc==SQLITE_OK
+ && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0
+ ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }
+
+#ifdef SQLITE_DEBUG
+ /* Ensure that all mappings in the Parse.pRename list really do map to
+ ** a part of the input string. */
+ if( rc==SQLITE_OK ){
+ int nSql = sqlite3Strlen30(zSql);
+ RenameToken *pToken;
+ for(pToken=p->pRename; pToken; pToken=pToken->pNext){
+ assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
+ }
+ }
+#endif
+
+ db->init.iDb = 0;
+ return rc;
+}
+
+static int renameEditSql(
+ sqlite3_context *pCtx, /* Return result here */
+ RenameCtx *pRename, /* Rename context */
+ const char *zSql, /* SQL statement to edit */
+ const char *zNew, /* New token text */
+ int bQuote /* True to always quote token */
+){
+ int nNew = sqlite3Strlen30(zNew);
+ int nSql = sqlite3Strlen30(zSql);
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+ int rc = SQLITE_OK;
+ char *zQuot;
+ char *zOut;
+ int nQuot;
+
+ /* Set zQuot to point to a buffer containing a quoted copy of the
+ ** identifier zNew. If the corresponding identifier in the original
+ ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to
+ ** point to zQuot so that all substitutions are made using the
+ ** quoted version of the new column name. */
+ zQuot = sqlite3_mprintf("\"%w\"", zNew);
+ if( zQuot==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ nQuot = sqlite3Strlen30(zQuot);
+ }
+ if( bQuote ){
+ zNew = zQuot;
+ nNew = nQuot;
+ }
+
+ /* At this point pRename->pList contains a list of RenameToken objects
+ ** corresponding to all tokens in the input SQL that must be replaced
+ ** with the new column name. All that remains is to construct and
+ ** return the edited SQL string. */
+ assert( nQuot>=nNew );
+ zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
+ if( zOut ){
+ int nOut = nSql;
+ memcpy(zOut, zSql, nSql);
+ while( pRename->pList ){
+ int iOff; /* Offset of token to replace in zOut */
+ RenameToken *pBest = renameColumnTokenNext(pRename);
+
+ u32 nReplace;
+ const char *zReplace;
+ if( sqlite3IsIdChar(*pBest->t.z) ){
+ nReplace = nNew;
+ zReplace = zNew;
+ }else{
+ nReplace = nQuot;
+ zReplace = zQuot;
+ }
+
+ iOff = pBest->t.z - zSql;
+ if( pBest->t.n!=nReplace ){
+ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
+ nOut - (iOff + pBest->t.n)
+ );
+ nOut += nReplace - pBest->t.n;
+ zOut[nOut] = '\0';
+ }
+ memcpy(&zOut[iOff], zReplace, nReplace);
+ sqlite3DbFree(db, pBest);
+ }
+
+ sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT);
+ sqlite3DbFree(db, zOut);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+
+ sqlite3_free(zQuot);
+ return rc;
+}
+
+static int renameResolveTrigger(
+ Parse *pParse,
+ const char *zDb
+){
+ sqlite3 *db = pParse->db;
+ TriggerStep *pStep;
+ NameContext sNC;
+ int rc = SQLITE_OK;
+
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
+ pParse->pTriggerTab = sqlite3FindTable(db, pParse->pNewTrigger->table, zDb);
+ pParse->eTriggerOp = pParse->pNewTrigger->op;
+
+ /* Resolve symbols in WHEN clause */
+ if( pParse->pNewTrigger->pWhen ){
+ rc = sqlite3ResolveExprNames(&sNC, pParse->pNewTrigger->pWhen);
+ }
+
+ for(pStep=pParse->pNewTrigger->step_list;
+ rc==SQLITE_OK && pStep;
+ pStep=pStep->pNext
+ ){
+ if( pStep->pSelect ){
+ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
+ if( pParse->nErr ) rc = pParse->rc;
+ }
+ if( rc==SQLITE_OK && pStep->zTarget ){
+ Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
+ if( pTarget==0 ){
+ rc = SQLITE_ERROR;
+ }else{
+ SrcList sSrc;
+ memset(&sSrc, 0, sizeof(sSrc));
+ sSrc.nSrc = 1;
+ sSrc.a[0].zName = pStep->zTarget;
+ sSrc.a[0].pTab = pTarget;
+ sNC.pSrcList = &sSrc;
+ if( pStep->pWhere ){
+ rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
+ }
+ assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
+ if( pStep->pUpsert ){
+ Upsert *pUpsert = pStep->pUpsert;
+ assert( rc==SQLITE_OK );
+ pUpsert->pUpsertSrc = &sSrc;
+ sNC.uNC.pUpsert = pUpsert;
+ sNC.ncFlags = NC_UUpsert;
+ rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
+ if( rc==SQLITE_OK ){
+ ExprList *pUpsertSet = pUpsert->pUpsertSet;
+ rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
+ }
+ sNC.ncFlags = 0;
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
+ TriggerStep *pStep;
+
+ /* Find tokens to edit in WHEN clause */
+ sqlite3WalkExpr(pWalker, pTrigger->pWhen);
+
+ /* Find tokens to edit in trigger steps */
+ for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
+ sqlite3WalkSelect(pWalker, pStep->pSelect);
+ sqlite3WalkExpr(pWalker, pStep->pWhere);
+ sqlite3WalkExprList(pWalker, pStep->pExprList);
+ if( pStep->pUpsert ){
+ Upsert *pUpsert = pStep->pUpsert;
+ sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget);
+ sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet);
+ sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
+ sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
+ }
+ }
+}
+
/*
** SQL function:
**
@@ -1191,6 +1185,7 @@ static void renameColumnFunc(
int nNew = sqlite3_value_bytes(argv[6]);
int bQuote = sqlite3_value_int(argv[7]);
const char *zOld;
+ int bTemp = 0;
int rc;
char *zErr = 0;
@@ -1199,8 +1194,6 @@ static void renameColumnFunc(
Index *pIdx;
char *zOut = 0;
- char *zQuot = 0; /* Quoted version of zNew */
- int nQuot = 0; /* Length of zQuot in bytes */
int i;
Table *pTab;
@@ -1219,54 +1212,7 @@ static void renameColumnFunc(
memset(&sCtx, 0, sizeof(sCtx));
sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
- /* Parse the SQL statement passed as the first argument. If no error
- ** occurs and the parse does not result in a new table, index or
- ** trigger object, the database must be corrupt. */
- memset(&sParse, 0, sizeof(sParse));
- sParse.eParseMode = PARSE_MODE_RENAME_COLUMN;
- sParse.db = db;
- sParse.nQueryLoop = 1;
- rc = sqlite3RunParser(&sParse, zSql, &zErr);
- assert( sParse.zErrMsg==0 );
- assert( rc!=SQLITE_OK || zErr==0 );
- assert( (!!sParse.pNewTable)+(!!sParse.pNewIndex)+(!!sParse.pNewTrigger)<2 );
- sParse.zErrMsg = zErr;
- if( db->mallocFailed ) rc = SQLITE_NOMEM;
- if( rc==SQLITE_OK
- && sParse.pNewTable==0 && sParse.pNewIndex==0 && sParse.pNewTrigger==0
- ){
- rc = SQLITE_CORRUPT_BKPT;
- }
-
-#ifdef SQLITE_DEBUG
- /* Ensure that all mappings in the Parse.pRename list really do map to
- ** a part of the input string. */
- 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] );
- }
- }
-#endif
-
- /* Set zQuot to point to a buffer containing a quoted copy of the
- ** identifier zNew. If the corresponding identifier in the original
- ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to
- ** point to zQuot so that all substitutions are made using the
- ** quoted version of the new column name. */
- if( rc==SQLITE_OK ){
- zQuot = sqlite3_mprintf("\"%w\"", zNew);
- if( zQuot==0 ){
- rc = SQLITE_NOMEM;
- }else{
- nQuot = sqlite3Strlen30(zQuot);
- }
- }
- if( bQuote ){
- zNew = zQuot;
- nNew = nQuot;
- }
+ rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp);
/* Find tokens that need to be replaced. */
memset(&sWalker, 0, sizeof(Walker));
@@ -1325,150 +1271,207 @@ static void renameColumnFunc(
}else{
/* A trigger */
TriggerStep *pStep;
- NameContext sNC;
- memset(&sNC, 0, sizeof(sNC));
- sNC.pParse = &sParse;
- sParse.pTriggerTab = sqlite3FindTable(db, sParse.pNewTrigger->table, zDb);
- sParse.eTriggerOp = sParse.pNewTrigger->op;
-
- /* Resolve symbols in WHEN clause */
- if( sParse.pNewTrigger->pWhen ){
- rc = sqlite3ResolveExprNames(&sNC, sParse.pNewTrigger->pWhen);
- }
+ rc = renameResolveTrigger(&sParse, zDb);
+ if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
- for(pStep=sParse.pNewTrigger->step_list;
- rc==SQLITE_OK && pStep;
- pStep=pStep->pNext
- ){
- if( pStep->pSelect ){
- sqlite3SelectPrep(&sParse, pStep->pSelect, &sNC);
- if( sParse.nErr ) rc = sParse.rc;
- }
- if( rc==SQLITE_OK && pStep->zTarget ){
+ for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
+ if( pStep->zTarget ){
Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb);
- if( pTarget==0 ){
- rc = SQLITE_ERROR;
- }else{
- SrcList sSrc;
- memset(&sSrc, 0, sizeof(sSrc));
- sSrc.nSrc = 1;
- sSrc.a[0].zName = pStep->zTarget;
- sSrc.a[0].pTab = pTarget;
- sNC.pSrcList = &sSrc;
- if( pStep->pWhere ){
- rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
- }
- assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
+ if( pTarget==pTab ){
if( pStep->pUpsert ){
- Upsert *pUpsert = pStep->pUpsert;
- assert( rc==SQLITE_OK );
- pUpsert->pUpsertSrc = &sSrc;
- sNC.uNC.pUpsert = pUpsert;
- sNC.ncFlags = NC_UUpsert;
- rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
- if( rc==SQLITE_OK ){
- ExprList *pUpsertSet = pUpsert->pUpsertSet;
- if( pTarget==pTab ){
- renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld);
- }
- rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
- }
- sNC.ncFlags = 0;
- }
-
- if( rc==SQLITE_OK && pTarget==pTab ){
- renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld);
- renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld);
+ ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet;
+ renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld);
}
+ renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld);
+ renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld);
}
}
}
- if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
/* Find tokens to edit in UPDATE OF clause */
if( sParse.pTriggerTab==pTab ){
renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld);
}
- /* Find tokens to edit in WHEN clause */
- sqlite3WalkExpr(&sWalker, sParse.pNewTrigger->pWhen);
+ /* Find tokens to edit in various expressions and selects */
+ renameWalkTrigger(&sWalker, sParse.pNewTrigger);
+ }
- /* Find tokens to edit in trigger steps */
- for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
- sqlite3WalkSelect(&sWalker, pStep->pSelect);
- sqlite3WalkExpr(&sWalker, pStep->pWhere);
- sqlite3WalkExprList(&sWalker, pStep->pExprList);
- if( pStep->pUpsert ){
- Upsert *pUpsert = pStep->pUpsert;
- sqlite3WalkExprList(&sWalker, pUpsert->pUpsertTarget);
- sqlite3WalkExprList(&sWalker, pUpsert->pUpsertSet);
- sqlite3WalkExpr(&sWalker, pUpsert->pUpsertWhere);
- sqlite3WalkExpr(&sWalker, pUpsert->pUpsertTargetWhere);
- }
+ assert( rc==SQLITE_OK );
+ rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote);
+
+renameColumnFunc_done:
+ if( rc!=SQLITE_OK ){
+ if( sParse.zErrMsg ){
+ renameColumnParseError(context, (bQuote<0), argv[1], argv[2], &sParse);
+ }else{
+ sqlite3_result_error_code(context, rc);
}
}
- /* At this point sCtx.pList contains a list of RenameToken objects
- ** corresponding to all tokens in the input SQL that must be replaced
- ** with the new column name. All that remains is to construct and
- ** return the edited SQL string. */
- assert( rc==SQLITE_OK );
- assert( nQuot>=nNew );
- zOut = sqlite3DbMallocZero(db, nSql + sCtx.nList*nQuot + 1);
- if( zOut ){
- int nOut = nSql;
- memcpy(zOut, zSql, nSql);
- while( sCtx.pList ){
- int iOff; /* Offset of token to replace in zOut */
- RenameToken *pBest = renameColumnTokenNext(&sCtx);
+ 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);
+ sqlite3DbFree(db, sParse.zErrMsg);
+ sqlite3ParserReset(&sParse);
+ sqlite3BtreeLeaveAll(db);
+}
- u32 nReplace;
- const char *zReplace;
- if( sqlite3IsIdChar(*pBest->t.z) ){
- nReplace = nNew;
- zReplace = zNew;
+static int renameTableExprCb(Walker *pWalker, Expr *pExpr){
+ RenameCtx *p = pWalker->u.pRename;
+ if( pExpr->op==TK_COLUMN && p->pTab==pExpr->pTab ){
+ renameTokenFind(pWalker->pParse, p, (void*)&pExpr->pTab);
+ }
+ return WRC_Continue;
+}
+
+/*
+** This is a Walker select callback.
+*/
+static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
+ int i;
+ RenameCtx *p = pWalker->u.pRename;
+ SrcList *pSrc = pSelect->pSrc;
+ for(i=0; i<pSrc->nSrc; i++){
+ struct SrcList_item *pItem = &pSrc->a[i];
+ if( pItem->pTab==p->pTab ){
+ renameTokenFind(pWalker->pParse, p, pItem->zName);
+ }
+ }
+
+ return WRC_Continue;
+}
+
+
+/*
+** This C function implements an SQL user function that is used by SQL code
+** generated by the ALTER TABLE ... RENAME command to modify the definition
+** of any foreign key constraints that use the table being renamed as the
+** parent table. It is passed three arguments:
+**
+** 1) The complete text of the CREATE TABLE statement being modified,
+** 2) The old name of the table being renamed, and
+** 3) The new name of the table being renamed.
+**
+** It returns the new CREATE TABLE statement. For example:
+**
+** sqlite_rename_table('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3')
+** -> 'CREATE TABLE t1(a REFERENCES t3)'
+*/
+static void renameTableFunc(
+ sqlite3_context *context,
+ int NotUsed,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ char *zOutput = 0;
+ char *zResult;
+ unsigned char const *zDb = sqlite3_value_text(argv[0]);
+ unsigned char const *zInput = sqlite3_value_text(argv[1]);
+ unsigned char const *zOld = sqlite3_value_text(argv[2]);
+ unsigned char const *zNew = sqlite3_value_text(argv[3]);
+ int bTemp = sqlite3_value_int(argv[4]);
+
+ unsigned const char *z; /* Pointer to token */
+ int n; /* Length of token z */
+ int token; /* Type of token */
+
+ Parse sParse;
+ int rc;
+ int bQuote = 1;
+ RenameCtx sCtx;
+ Walker sWalker;
+
+ if( zInput==0 || zOld==0 || zNew==0 ) return;
+
+ memset(&sCtx, 0, sizeof(RenameCtx));
+ sCtx.pTab = sqlite3FindTable(db, zOld, zDb);
+ memset(&sWalker, 0, sizeof(Walker));
+ sWalker.pParse = &sParse;
+ sWalker.xExprCallback = renameTableExprCb;
+ sWalker.xSelectCallback = renameTableSelectCb;
+ sWalker.u.pRename = &sCtx;
+
+ sqlite3BtreeEnterAll(db);
+
+ rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
+
+ if( rc==SQLITE_OK ){
+ if( sParse.pNewTable ){
+ Table *pTab = sParse.pNewTable;
+
+ if( pTab->pSelect ){
+ NameContext sNC;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = &sParse;
+
+ sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
+ if( sParse.nErr ) rc = sParse.rc;
+ sqlite3WalkSelect(&sWalker, pTab->pSelect);
}else{
- nReplace = nQuot;
- zReplace = zQuot;
+ /* Modify any FK definitions to point to the new table. */
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+ FKey *pFKey;
+ for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){
+ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo);
+ }
+ }
+#endif
+
+ /* If this is the table being altered, fix any table refs in CHECK
+ ** expressions. Also update the name that appears right after the
+ ** "CREATE [VIRTUAL] TABLE" bit. */
+ if( sqlite3_stricmp(zOld, pTab->zName)==0 ){
+ sCtx.pTab = pTab;
+ sqlite3WalkExprList(&sWalker, pTab->pCheck);
+ renameTokenFind(&sParse, &sCtx, pTab->zName);
+ }
}
+ }
- iOff = pBest->t.z - zSql;
- if( pBest->t.n!=nReplace ){
- memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
- nOut - (iOff + pBest->t.n)
- );
- nOut += nReplace - pBest->t.n;
- zOut[nOut] = '\0';
+ else if( sParse.pNewIndex ){
+ renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName);
+ sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
+ }
+
+#ifndef SQLITE_OMIT_TRIGGER
+ else if( sParse.pNewTrigger ){
+ Trigger *pTrigger = sParse.pNewTrigger;
+ TriggerStep *pStep;
+ if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld)
+ && sCtx.pTab->pSchema==pTrigger->pTabSchema
+ ){
+ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table);
+ }
+
+ rc = renameResolveTrigger(&sParse, zDb);
+ if( rc==SQLITE_OK ){
+ renameWalkTrigger(&sWalker, pTrigger);
+ }
+
+ for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
+ if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
+ renameTokenFind(&sParse, &sCtx, pStep->zTarget);
+ }
}
- memcpy(&zOut[iOff], zReplace, nReplace);
- sqlite3DbFree(db, pBest);
}
+#endif
+ }
- sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
- sqlite3DbFree(db, zOut);
- }else{
- rc = SQLITE_NOMEM;
+ if( rc==SQLITE_OK ){
+ rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote);
}
-renameColumnFunc_done:
if( rc!=SQLITE_OK ){
- if( sParse.zErrMsg ){
- renameColumnParseError(context, (bQuote<0), argv[1], argv[2], &sParse);
- }else{
- sqlite3_result_error_code(context, rc);
- }
+ sqlite3_result_error_code(context, rc);
}
-
if( sParse.pVdbe ){
sqlite3VdbeFinalize(sParse.pVdbe);
}
@@ -1479,8 +1482,9 @@ renameColumnFunc_done:
renameTokenFree(db, sCtx.pList);
sqlite3DbFree(db, sParse.zErrMsg);
sqlite3ParserReset(&sParse);
- sqlite3_free(zQuot);
sqlite3BtreeLeaveAll(db);
+
+ return;
}
/*
@@ -1488,14 +1492,8 @@ renameColumnFunc_done:
*/
void sqlite3AlterFunctions(void){
static FuncDef aAlterTableFuncs[] = {
- FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
FUNCTION(sqlite_rename_column, 8, 0, 0, renameColumnFunc),
-#ifndef SQLITE_OMIT_TRIGGER
- FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
-#endif
-#ifndef SQLITE_OMIT_FOREIGN_KEY
- FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
-#endif
+ FUNCTION(sqlite_rename_table, 5, 0, 0, renameTableFunc),
};
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
diff --git a/src/build.c b/src/build.c
index 7f8013a0c..4ab467b62 100644
--- a/src/build.c
+++ b/src/build.c
@@ -783,7 +783,7 @@ int sqlite3TwoPartName(
return -1;
}
}else{
- assert( db->init.iDb==0 || db->init.busy
+ assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT
|| (db->mDbFlags & DBFLAG_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
@@ -878,6 +878,9 @@ void sqlite3StartTable(
}
if( !OMIT_TEMPDB && isTemp ) iDb = 1;
zName = sqlite3NameFromToken(db, pName);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)zName, pName);
+ }
}
pParse->sNameToken = *pName;
if( zName==0 ) return;
@@ -1072,7 +1075,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
}
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
if( z==0 ) return;
- if( IN_RENAME_COLUMN ) sqlite3RenameTokenMap(pParse, (void*)z, pName);
+ if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName);
memcpy(z, pName->z, pName->n);
z[pName->n] = 0;
sqlite3Dequote(z);
@@ -1370,7 +1373,7 @@ void sqlite3AddPrimaryKey(
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
&& sortOrder!=SQLITE_SO_DESC
){
- if( IN_RENAME_COLUMN && pList ){
+ if( IN_RENAME_OBJECT && pList ){
sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr);
}
pTab->iPKey = iCol;
@@ -2175,7 +2178,7 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
p->pSelect = pSelect;
pSelect = 0;
}else{
@@ -2748,6 +2751,9 @@ void sqlite3CreateForeignKey(
pFKey->pNextFrom = p->pFKey;
z = (char*)&pFKey->aCol[nCol];
pFKey->zTo = z;
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)z, pTo);
+ }
memcpy(z, pTo->z, pTo->n);
z[pTo->n] = 0;
sqlite3Dequote(z);
@@ -2770,7 +2776,7 @@ void sqlite3CreateForeignKey(
pFromCol->a[i].zName);
goto fk_end;
}
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName);
}
}
@@ -2779,7 +2785,7 @@ void sqlite3CreateForeignKey(
for(i=0; i<nCol; i++){
int n = sqlite3Strlen30(pToCol->a[i].zName);
pFKey->aCol[i].zCol = z;
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName);
}
memcpy(z, pToCol->a[i].zName, n);
@@ -3114,7 +3120,7 @@ void sqlite3CreateIndex(
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto exit_create_index;
}
- if( !IN_RENAME_COLUMN ){
+ if( !IN_RENAME_OBJECT ){
if( !db->init.busy ){
if( sqlite3FindTable(db, zName, 0)!=0 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
@@ -3151,7 +3157,7 @@ void sqlite3CreateIndex(
/* Check for authorization to create an index.
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
- if( !IN_RENAME_COLUMN ){
+ if( !IN_RENAME_OBJECT ){
const char *zDb = pDb->zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
goto exit_create_index;
@@ -3239,7 +3245,7 @@ void sqlite3CreateIndex(
** index key.
*/
pListItem = pList->a;
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
pIndex->aColExpr = pList;
pList = 0;
}
@@ -3399,7 +3405,7 @@ void sqlite3CreateIndex(
}
}
- if( !IN_RENAME_COLUMN ){
+ if( !IN_RENAME_OBJECT ){
/* Link the new Index structure to its table and to the other
** in-memory database structures.
@@ -3517,7 +3523,7 @@ void sqlite3CreateIndex(
}
pIndex = 0;
}
- else if( IN_RENAME_COLUMN ){
+ else if( IN_RENAME_OBJECT ){
assert( pParse->pNewIndex==0 );
pParse->pNewIndex = pIndex;
pIndex = 0;
@@ -3713,7 +3719,7 @@ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
return 0;
}
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
- if( IN_RENAME_COLUMN && pList->a[i].zName ){
+ if( IN_RENAME_OBJECT && pList->a[i].zName ){
sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
}
return pList;
@@ -3962,6 +3968,10 @@ SrcList *sqlite3SrcListAppendFromTerm(
}
assert( p->nSrc>0 );
pItem = &p->a[p->nSrc-1];
+ if( IN_RENAME_OBJECT && pItem->zName ){
+ Token *pToken = (pDatabase && pDatabase->z) ? pDatabase : pTable;
+ sqlite3RenameTokenMap(pParse, pItem->zName, pToken);
+ }
assert( pAlias!=0 );
if( pAlias->n ){
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
diff --git a/src/expr.c b/src/expr.c
index 6f9c73307..701f10856 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1666,7 +1666,7 @@ void sqlite3ExprListSetName(
assert( pItem->zName==0 );
pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
if( dequote ) sqlite3Dequote(pItem->zName);
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName);
}
}
diff --git a/src/parse.y b/src/parse.y
index 44e300e19..8bf5d83fc 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -325,7 +325,7 @@ ccons ::= DEFAULT scanpt id(X). {
sqlite3ExprIdToTrueFalse(p);
testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) );
}
- sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n);
+ sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n);
}
// In addition to the type name, we also care about the primary key and
@@ -683,10 +683,14 @@ dbnm(A) ::= DOT nm(X). {A = X;}
%type fullname {SrcList*}
%destructor fullname {sqlite3SrcListDelete(pParse->db, $$);}
-fullname(A) ::= nm(X).
- {A = sqlite3SrcListAppend(pParse->db,0,&X,0); /*A-overwrites-X*/}
-fullname(A) ::= nm(X) DOT nm(Y).
- {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); /*A-overwrites-X*/}
+fullname(A) ::= nm(X). {
+ A = sqlite3SrcListAppend(pParse->db,0,&X,0);
+ if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &X);
+}
+fullname(A) ::= nm(X) DOT nm(Y). {
+ A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);
+ if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y);
+}
%type xfullname {SrcList*}
%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);}
@@ -954,7 +958,7 @@ idlist(A) ::= nm(Y).
#if SQLITE_MAX_EXPR_DEPTH>0
p->nHeight = 1;
#endif
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t);
}
}
@@ -970,7 +974,10 @@ expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
- if( IN_RENAME_COLUMN ) sqlite3RenameTokenMap(pParse, (void*)temp2, &Y);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)temp2, &Y);
+ sqlite3RenameTokenMap(pParse, (void*)temp1, &X);
+ }
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
@@ -978,7 +985,10 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
- if( IN_RENAME_COLUMN ) sqlite3RenameTokenMap(pParse, (void*)temp3, &Z);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)temp3, &Z);
+ sqlite3RenameTokenMap(pParse, (void*)temp2, &Y);
+ }
A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
@@ -1277,6 +1287,9 @@ cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
sqlite3CreateIndex(pParse, &X, &D,
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
&S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF);
+ if( IN_RENAME_OBJECT && pParse->pNewIndex ){
+ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &Y);
+ }
}
%type uniqueflag {int}
@@ -1325,9 +1338,6 @@ uniqueflag(A) ::= . {A = OE_None;}
pIdToken->n, pIdToken->z);
}
sqlite3ExprListSetName(pParse, p, pIdToken, 1);
- if( IN_RENAME_COLUMN && p ){
- sqlite3RenameTokenMap(pParse, (void*)(p->a[p->nExpr-1].zName), pIdToken);
- }
return p;
}
} // end %include
diff --git a/src/prepare.c b/src/prepare.c
index 4d4b98d8a..602e4dc49 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -93,7 +93,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
- assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
+ /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
diff --git a/src/resolve.c b/src/resolve.c
index fb3833228..9fb4d4c63 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -264,6 +264,9 @@ static int lookupName(
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
continue;
}
+ if( IN_RENAME_OBJECT && pItem->zAlias ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->pTab);
+ }
}
if( 0==(cntTab++) ){
pMatch = pItem;
@@ -349,7 +352,7 @@ static int lookupName(
#ifndef SQLITE_OMIT_UPSERT
if( pExpr->iTable==2 ){
testcase( iCol==(-1) );
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
pExpr->iColumn = iCol;
pExpr->pTab = pTab;
eNewExprOp = TK_COLUMN;
@@ -442,7 +445,7 @@ static int lookupName(
cnt = 1;
pMatch = 0;
assert( zTab==0 && zDb==0 );
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
}
goto lookupname_end;
@@ -672,21 +675,25 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
zTable = 0;
zColumn = pExpr->u.zToken;
}else{
+ Expr *pLeft = pExpr->pLeft;
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
- zTable = pExpr->pLeft->u.zToken;
}else{
assert( pRight->op==TK_DOT );
- zDb = pExpr->pLeft->u.zToken;
- zTable = pRight->pLeft->u.zToken;
+ zDb = pLeft->u.zToken;
+ pLeft = pRight->pLeft;
pRight = pRight->pRight;
}
+ zTable = pLeft->u.zToken;
zColumn = pRight->u.zToken;
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
}
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, (void*)&pExpr->pTab, (void*)pLeft);
+ }
}
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
}
@@ -769,7 +776,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
- if( 0==IN_RENAME_COLUMN ){
+ if( 0==IN_RENAME_OBJECT ){
#ifndef SQLITE_OMIT_WINDOWFUNC
assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
|| (pDef->xValue==0 && pDef->xInverse==0)
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 25f101d90..d8e3a795d 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3123,6 +3123,7 @@ struct Parse {
#define PARSE_MODE_NORMAL 0
#define PARSE_MODE_DECLARE_VTAB 1
#define PARSE_MODE_RENAME_COLUMN 2
+#define PARSE_MODE_RENAME_TABLE 3
/*
** Sizes and pointers of various parts of the Parse object.
@@ -3142,9 +3143,9 @@ struct Parse {
#endif
#if defined(SQLITE_OMIT_ALTERTABLE)
- #define IN_RENAME_COLUMN 0
+ #define IN_RENAME_OBJECT 0
#else
- #define IN_RENAME_COLUMN (pParse->eParseMode==PARSE_MODE_RENAME_COLUMN)
+ #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN)
#endif
#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
diff --git a/src/tokenize.c b/src/tokenize.c
index 94a5b8515..262144ff7 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -695,7 +695,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
- if( !IN_RENAME_COLUMN ){
+ if( !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
diff --git a/src/trigger.c b/src/trigger.c
index 330e14ea7..dd6224da6 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -181,7 +181,7 @@ void sqlite3BeginTrigger(
goto trigger_cleanup;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- if( !IN_RENAME_COLUMN ){
+ if( !IN_RENAME_OBJECT ){
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
@@ -214,7 +214,7 @@ void sqlite3BeginTrigger(
}
#ifndef SQLITE_OMIT_AUTHORIZATION
- if( !IN_RENAME_COLUMN ){
+ if( !IN_RENAME_OBJECT ){
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[iTabDb].zDbSName;
@@ -248,7 +248,8 @@ void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
pTrigger->pWhen = pWhen;
pWhen = 0;
}else{
@@ -305,7 +306,7 @@ void sqlite3FinishTrigger(
}
#ifndef SQLITE_OMIT_ALTERTABLE
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
assert( !db->init.busy );
pParse->pNewTrigger = pTrig;
pTrig = 0;
@@ -353,7 +354,7 @@ void sqlite3FinishTrigger(
triggerfinish_cleanup:
sqlite3DeleteTrigger(db, pTrig);
- assert( IN_RENAME_COLUMN || !pParse->pNewTrigger );
+ assert( IN_RENAME_OBJECT || !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(db, pStepList);
}
@@ -400,12 +401,13 @@ TriggerStep *sqlite3TriggerSelectStep(
** If an OOM error occurs, NULL is returned and db->mallocFailed is set.
*/
static TriggerStep *triggerStepAllocate(
- sqlite3 *db, /* Database connection */
+ Parse *pParse, /* Parser context */
u8 op, /* Trigger opcode */
Token *pName, /* The target name */
const char *zStart, /* Start of SQL text */
const char *zEnd /* End of SQL text */
){
+ sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
@@ -416,6 +418,9 @@ static TriggerStep *triggerStepAllocate(
pTriggerStep->zTarget = z;
pTriggerStep->op = op;
pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName);
+ }
}
return pTriggerStep;
}
@@ -442,9 +447,9 @@ TriggerStep *sqlite3TriggerInsertStep(
assert(pSelect != 0 || db->mallocFailed);
- pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
+ pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd);
if( pTriggerStep ){
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
pTriggerStep->pSelect = pSelect;
pSelect = 0;
}else{
@@ -481,9 +486,9 @@ TriggerStep *sqlite3TriggerUpdateStep(
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
+ pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
if( pTriggerStep ){
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pEList = 0;
@@ -514,9 +519,9 @@ TriggerStep *sqlite3TriggerDeleteStep(
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
+ pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd);
if( pTriggerStep ){
- if( IN_RENAME_COLUMN ){
+ if( IN_RENAME_OBJECT ){
pTriggerStep->pWhere = pWhere;
pWhere = 0;
}else{