Skip to content

Commit 62c1497

Browse files
lidezhutenfyzhong
authored andcommitted
schemastore: fix rename tables when tidb version <= v8.1.x (#4388)
close #4392
1 parent 920ec14 commit 62c1497

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
@@ -519,7 +519,7 @@ func getSchemaID(tableMap map[int64]*BasicTableInfo, tableID int64) int64 {
519519
// schemaName should be "Name.O"
520520
func findSchemaIDByName(databaseMap map[int64]*BasicDatabaseInfo, schemaName string) (int64, bool) {
521521
for id, info := range databaseMap {
522-
if info.Name == schemaName {
522+
if strings.EqualFold(info.Name, schemaName) {
523523
return id, true
524524
}
525525
}
@@ -529,7 +529,7 @@ func findSchemaIDByName(databaseMap map[int64]*BasicDatabaseInfo, schemaName str
529529
// tableName should be "Name.O"
530530
func findTableIDByName(tableMap map[int64]*BasicTableInfo, schemaID int64, tableName string) (int64, bool) {
531531
for id, info := range tableMap {
532-
if info.SchemaID == schemaID && info.Name == tableName {
532+
if info.SchemaID == schemaID && strings.EqualFold(info.Name, tableName) {
533533
return id, true
534534
}
535535
}
@@ -599,7 +599,7 @@ func buildPersistedDDLEventForDropView(args buildPersistedDDLEventFuncArgs) Pers
599599
// We don't store the relationship: view_id -> table_name, get table name from args.job
600600
event.TableName = args.job.TableName
601601
// The query in job maybe "DROP VIEW test1.view1, test2.view2", we need rebuild it here.
602-
event.Query = fmt.Sprintf("DROP VIEW `%s`.`%s`", event.SchemaName, event.TableName)
602+
event.Query = fmt.Sprintf("DROP VIEW %s", common.QuoteSchema(event.SchemaName, event.TableName))
603603
return event
604604
}
605605

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

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

792799
if strings.HasSuffix(upperQuery, "WITHOUT VALIDATION") {
793800
event.Query += " WITHOUT VALIDATION"
@@ -799,6 +806,41 @@ func buildPersistedDDLEventForExchangePartition(args buildPersistedDDLEventFuncA
799806
return event
800807
}
801808

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

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

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

0 commit comments

Comments
 (0)