Skip to content

Commit 4def9c1

Browse files
lidezhuti-chi-bot
authored andcommitted
schemastore: fix rename tables when tidb version <= v8.1.x (pingcap#4388)
close pingcap#4392
1 parent f254ff0 commit 4def9c1

File tree

4 files changed

+524
-20
lines changed

4 files changed

+524
-20
lines changed

logservice/schemastore/persist_storage_ddl_handlers.go

Lines changed: 108 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ func getSchemaID(tableMap map[int64]*BasicTableInfo, tableID int64) int64 {
520520
// schemaName should be "Name.O"
521521
func findSchemaIDByName(databaseMap map[int64]*BasicDatabaseInfo, schemaName string) (int64, bool) {
522522
for id, info := range databaseMap {
523-
if info.Name == schemaName {
523+
if strings.EqualFold(info.Name, schemaName) {
524524
return id, true
525525
}
526526
}
@@ -530,7 +530,7 @@ func findSchemaIDByName(databaseMap map[int64]*BasicDatabaseInfo, schemaName str
530530
// tableName should be "Name.O"
531531
func findTableIDByName(tableMap map[int64]*BasicTableInfo, schemaID int64, tableName string) (int64, bool) {
532532
for id, info := range tableMap {
533-
if info.SchemaID == schemaID && info.Name == tableName {
533+
if info.SchemaID == schemaID && strings.EqualFold(info.Name, tableName) {
534534
return id, true
535535
}
536536
}
@@ -600,7 +600,7 @@ func buildPersistedDDLEventForDropView(args buildPersistedDDLEventFuncArgs) Pers
600600
// We don't store the relationship: view_id -> table_name, get table name from args.job
601601
event.TableName = args.job.TableName
602602
// The query in job maybe "DROP VIEW test1.view1, test2.view2", we need rebuild it here.
603-
event.Query = fmt.Sprintf("DROP VIEW `%s`.`%s`", event.SchemaName, event.TableName)
603+
event.Query = fmt.Sprintf("DROP VIEW %s", common.QuoteSchema(event.SchemaName, event.TableName))
604604
return event
605605
}
606606

@@ -662,7 +662,7 @@ func buildPersistedDDLEventForDropTable(args buildPersistedDDLEventFuncArgs) Per
662662
event.SchemaName = getSchemaName(args.databaseMap, event.SchemaID)
663663
event.TableName = getTableName(args.tableMap, event.TableID)
664664
// The query in job maybe "DROP TABLE test1.table1, test2.table2", we need rebuild it here.
665-
event.Query = fmt.Sprintf("DROP TABLE `%s`.`%s`", event.SchemaName, event.TableName)
665+
event.Query = fmt.Sprintf("DROP TABLE %s", common.QuoteSchema(event.SchemaName, event.TableName))
666666
return event
667667
}
668668

@@ -723,6 +723,11 @@ func buildPersistedDDLEventForRenameTable(args buildPersistedDDLEventFuncArgs) P
723723
//
724724
// InvolvingSchemaInfo returns the schema info involved in the job.
725725
// The value should be stored in lower case.
726+
//
727+
// InvolvingSchemaInfo may store normalized lower-case names,
728+
// while the original query can keep user-provided identifier case.
729+
// Prefer names parsed from the original query whenever possible.
730+
// See https://github.com/pingcap/ticdc/pull/2218 for background.
726731
oldSchemaName := args.job.InvolvingSchemaInfo[0].Database
727732
oldTableName := args.job.InvolvingSchemaInfo[0].Table
728733
stmt, err := parser.New().ParseOneStmt(args.job.Query, "", "")
@@ -744,9 +749,9 @@ func buildPersistedDDLEventForRenameTable(args buildPersistedDDLEventFuncArgs) P
744749
log.Error("unknown stmt type", zap.String("query", args.job.Query), zap.Any("stmt", stmt))
745750
}
746751
}
747-
event.Query = fmt.Sprintf("RENAME TABLE `%s`.`%s` TO `%s`.`%s`",
748-
oldSchemaName, oldTableName,
749-
event.SchemaName, event.TableName)
752+
event.Query = fmt.Sprintf("RENAME TABLE %s TO %s",
753+
common.QuoteSchema(oldSchemaName, oldTableName),
754+
common.QuoteSchema(event.SchemaName, event.TableName))
750755
}
751756
return event
752757
}
@@ -787,8 +792,10 @@ func buildPersistedDDLEventForExchangePartition(args buildPersistedDDLEventFuncA
787792
// Note that partition name should be parsed from original query, not the upperQuery.
788793
partName := strings.TrimSpace(event.Query[idx1:idx2])
789794
partName = strings.Replace(partName, "`", "", -1)
790-
event.Query = fmt.Sprintf("ALTER TABLE `%s`.`%s` EXCHANGE PARTITION `%s` WITH TABLE `%s`.`%s`",
791-
event.ExtraSchemaName, event.ExtraTableName, partName, event.SchemaName, event.TableName)
795+
event.Query = fmt.Sprintf("ALTER TABLE %s EXCHANGE PARTITION %s WITH TABLE %s",
796+
common.QuoteSchema(event.ExtraSchemaName, event.ExtraTableName),
797+
common.QuoteName(partName),
798+
common.QuoteSchema(event.SchemaName, event.TableName))
792799

793800
if strings.HasSuffix(upperQuery, "WITHOUT VALIDATION") {
794801
event.Query += " WITHOUT VALIDATION"
@@ -800,6 +807,41 @@ func buildPersistedDDLEventForExchangePartition(args buildPersistedDDLEventFuncA
800807
return event
801808
}
802809

810+
type renameTableQueryInfo struct {
811+
oldSchemaName string
812+
oldTableName string
813+
newSchemaName string
814+
newTableName string
815+
}
816+
817+
func parseRenameTablesQueryInfos(query string) ([]renameTableQueryInfo, bool) {
818+
if query == "" {
819+
return nil, false
820+
}
821+
stmt, err := parser.New().ParseOneStmt(query, "", "")
822+
if err != nil {
823+
log.Warn("parse rename tables query failed",
824+
zap.String("query", query),
825+
zap.Error(err))
826+
return nil, false
827+
}
828+
renameStmt, ok := stmt.(*ast.RenameTableStmt)
829+
if !ok {
830+
return nil, false
831+
}
832+
833+
queryInfos := make([]renameTableQueryInfo, 0, len(renameStmt.TableToTables))
834+
for _, tableToTable := range renameStmt.TableToTables {
835+
queryInfos = append(queryInfos, renameTableQueryInfo{
836+
oldSchemaName: tableToTable.OldTable.Schema.O,
837+
oldTableName: tableToTable.OldTable.Name.O,
838+
newSchemaName: tableToTable.NewTable.Schema.O,
839+
newTableName: tableToTable.NewTable.Name.O,
840+
})
841+
}
842+
return queryInfos, true
843+
}
844+
803845
func buildPersistedDDLEventForRenameTables(args buildPersistedDDLEventFuncArgs) PersistedDDLEvent {
804846
// TODO: does rename tables has the same problem(finished ts is not the real commit ts) with rename table?
805847
event := buildPersistedDDLEventCommon(args)
@@ -809,25 +851,71 @@ func buildPersistedDDLEventForRenameTables(args buildPersistedDDLEventFuncArgs)
809851
zap.String("query", args.job.Query),
810852
zap.Error(err))
811853
}
812-
if len(renameArgs.RenameTableInfos) != len(args.job.BinlogInfo.MultipleTableInfos) {
854+
renameTableInfos := renameArgs.RenameTableInfos
855+
multipleTableInfos := args.job.BinlogInfo.MultipleTableInfos
856+
if len(renameTableInfos) != len(multipleTableInfos) {
813857
log.Panic("should not happen",
814-
zap.Int("renameArgsLen", len(renameArgs.RenameTableInfos)),
815-
zap.Int("multipleTableInfosLen", len(args.job.BinlogInfo.MultipleTableInfos)))
858+
zap.Int("renameArgsLen", len(renameTableInfos)),
859+
zap.Int("multipleTableInfosLen", len(multipleTableInfos)),
860+
zap.String("query", args.job.Query))
861+
}
862+
863+
// RenameTableInfos may store normalized lower-case names,
864+
// while the original query can keep user-provided identifier case.
865+
// Prefer names parsed from the original query whenever possible.
866+
// See https://github.com/pingcap/ticdc/pull/2218 for background.
867+
queryInfos, queryParsed := parseRenameTablesQueryInfos(args.job.Query)
868+
if queryParsed && len(queryInfos) != len(renameTableInfos) {
869+
log.Panic("rename tables query info length is inconsistent with args",
870+
zap.Int("queryInfosLen", len(queryInfos)),
871+
zap.Int("renameArgsLen", len(renameTableInfos)),
872+
zap.String("query", args.job.Query))
873+
}
874+
875+
// TiDB <= v8.1 may emit empty old table names for RENAME TABLES args.
876+
// See https://github.com/pingcap/tidb/pull/64421 for the upstream fix.
877+
if !queryParsed && renameTableInfos[0].OldTableName.O == "" {
878+
// TODO: return error instead of falling back to args once builder supports error propagation.
879+
log.Warn("rename tables args miss old table name and query is unavailable, keep args as-is",
880+
zap.Int("tableCount", len(renameTableInfos)),
881+
zap.String("query", args.job.Query))
816882
}
817883

818884
var querys []string
819-
for _, info := range renameArgs.RenameTableInfos {
820-
event.ExtraSchemaIDs = append(event.ExtraSchemaIDs, info.OldSchemaID)
821-
event.ExtraSchemaNames = append(event.ExtraSchemaNames, info.OldSchemaName.O)
822-
event.ExtraTableNames = append(event.ExtraTableNames, info.OldTableName.O)
885+
for i, info := range renameTableInfos {
886+
oldSchemaID := info.OldSchemaID
887+
oldSchemaName := info.OldSchemaName.O
888+
oldTableName := info.OldTableName.O
889+
newSchemaName := getSchemaName(args.databaseMap, info.NewSchemaID)
890+
newTableName := info.NewTableName.O
891+
if queryParsed {
892+
queryInfo := queryInfos[i]
893+
if queryInfo.oldSchemaName != "" {
894+
oldSchemaName = queryInfo.oldSchemaName
895+
}
896+
if queryInfo.oldTableName != "" {
897+
oldTableName = queryInfo.oldTableName
898+
}
899+
if queryInfo.newSchemaName != "" {
900+
newSchemaName = queryInfo.newSchemaName
901+
}
902+
if queryInfo.newTableName != "" {
903+
newTableName = queryInfo.newTableName
904+
}
905+
}
906+
907+
event.ExtraSchemaIDs = append(event.ExtraSchemaIDs, oldSchemaID)
908+
event.ExtraSchemaNames = append(event.ExtraSchemaNames, oldSchemaName)
909+
event.ExtraTableNames = append(event.ExtraTableNames, oldTableName)
823910
event.SchemaIDs = append(event.SchemaIDs, info.NewSchemaID)
824-
SchemaName := getSchemaName(args.databaseMap, info.NewSchemaID)
825-
event.SchemaNames = append(event.SchemaNames, SchemaName)
826-
querys = append(querys, fmt.Sprintf("RENAME TABLE `%s`.`%s` TO `%s`.`%s`;", info.OldSchemaName.O, info.OldTableName.O, SchemaName, info.NewTableName.O))
911+
event.SchemaNames = append(event.SchemaNames, newSchemaName)
912+
querys = append(querys, fmt.Sprintf("RENAME TABLE %s TO %s;",
913+
common.QuoteSchema(oldSchemaName, oldTableName),
914+
common.QuoteSchema(newSchemaName, newTableName)))
827915
}
828916

829917
event.Query = strings.Join(querys, "")
830-
event.MultipleTableInfos = args.job.BinlogInfo.MultipleTableInfos
918+
event.MultipleTableInfos = multipleTableInfos
831919
// we have to reverse MultipleTableInfos to get correct schema name
832920
// see https://github.com/pingcap/tidb/issues/63710
833921
//

0 commit comments

Comments
 (0)