diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/alter.c | 868 | ||||
-rw-r--r-- | src/build.c | 34 | ||||
-rw-r--r-- | src/expr.c | 2 | ||||
-rw-r--r-- | src/parse.y | 32 | ||||
-rw-r--r-- | src/prepare.c | 2 | ||||
-rw-r--r-- | src/resolve.c | 21 | ||||
-rw-r--r-- | src/sqliteInt.h | 5 | ||||
-rw-r--r-- | src/tokenize.c | 2 | ||||
-rw-r--r-- | src/trigger.c | 29 |
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{ |