Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dumpling: check table-list types before dumping (#53683) #57106

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions dumpling/export/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -1146,9 +1146,24 @@
}

func prepareTableListToDump(tctx *tcontext.Context, conf *Config, db *sql.Conn) error {
if conf.specifiedTables || conf.SQL != "" {
if conf.SQL != "" {

Check warning on line 1149 in dumpling/export/dump.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/dump.go#L1149

Added line #L1149 was not covered by tests
return nil
}

ifSeqExists, err := CheckIfSeqExists(db)
if err != nil {
return err
}
var listType listTableType
if ifSeqExists {
listType = listTableByShowFullTables
} else {
listType = getListTableTypeByConf(conf)
}

Check warning on line 1162 in dumpling/export/dump.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/dump.go#L1153-L1162

Added lines #L1153 - L1162 were not covered by tests

if conf.specifiedTables {
return updateSpecifiedTablesMeta(tctx, db, conf.Tables, listType)
}

Check warning on line 1166 in dumpling/export/dump.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/dump.go#L1164-L1166

Added lines #L1164 - L1166 were not covered by tests
databases, err := prepareDumpingDatabases(tctx, conf, db)
if err != nil {
return err
Expand All @@ -1162,17 +1177,6 @@
tableTypes = append(tableTypes, TableTypeSequence)
}

ifSeqExists, err := CheckIfSeqExists(db)
if err != nil {
return err
}
var listType listTableType
if ifSeqExists {
listType = listTableByShowFullTables
} else {
listType = getListTableTypeByConf(conf)
}

conf.Tables, err = ListAllDatabasesTables(tctx, db, databases, listType, tableTypes...)
if err != nil {
return err
Expand Down
113 changes: 113 additions & 0 deletions dumpling/export/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,119 @@
_, _ = w.WriteString("SET collation_connection = @PREV_COLLATION_CONNECTION;\n")
}

// updateSpecifiedTablesMeta updates DatabaseTables with correct table type and avg row size.
func updateSpecifiedTablesMeta(tctx *tcontext.Context, db *sql.Conn, dbTables DatabaseTables, listType listTableType) error {
var (
schema, table, tableTypeStr string
tableType TableType
avgRowLength uint64
err error
)
switch listType {
case listTableByInfoSchema:
dbNames := make([]string, 0, len(dbTables))
for db := range dbTables {
dbNames = append(dbNames, fmt.Sprintf("'%s'", db))
}
query := fmt.Sprintf("SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE,AVG_ROW_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA IN (%s)", strings.Join(dbNames, ","))
if err := simpleQueryWithArgs(tctx, db, func(rows *sql.Rows) error {
var (
sqlAvgRowLength sql.NullInt64
err2 error
)
if err2 = rows.Scan(&schema, &table, &tableTypeStr, &sqlAvgRowLength); err != nil {
return errors.Trace(err2)
}

Check warning on line 271 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L250-L271

Added lines #L250 - L271 were not covered by tests

tbls, ok := dbTables[schema]
if !ok {
return nil
}
for _, tbl := range tbls {
if tbl.Name == table {
tableType, err2 = ParseTableType(tableTypeStr)
if err2 != nil {
return errors.Trace(err2)
}
if sqlAvgRowLength.Valid {
avgRowLength = uint64(sqlAvgRowLength.Int64)
} else {
avgRowLength = 0
}
tbl.Type = tableType
tbl.AvgRowLength = avgRowLength

Check warning on line 289 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L273-L289

Added lines #L273 - L289 were not covered by tests
}
}
return nil
}, query); err != nil {
return errors.Annotatef(err, "sql: %s", query)
}
return nil
case listTableByShowFullTables:
for schema, tbls := range dbTables {
query := fmt.Sprintf("SHOW FULL TABLES FROM `%s`",
escapeString(schema))
if err := simpleQueryWithArgs(tctx, db, func(rows *sql.Rows) error {
var err2 error
if err2 = rows.Scan(&table, &tableTypeStr); err != nil {
return errors.Trace(err2)
}
for _, tbl := range tbls {
if tbl.Name == table {
tableType, err2 = ParseTableType(tableTypeStr)
if err2 != nil {
return errors.Trace(err2)
}
tbl.Type = tableType

Check warning on line 312 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L292-L312

Added lines #L292 - L312 were not covered by tests
}
}
return nil
}, query); err != nil {
return errors.Annotatef(err, "sql: %s", query)
}

Check warning on line 318 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L315-L318

Added lines #L315 - L318 were not covered by tests
}
return nil
default:
const queryTemplate = "SHOW TABLE STATUS FROM `%s`"
for schema, tbls := range dbTables {
query := fmt.Sprintf(queryTemplate, escapeString(schema))
rows, err := db.QueryContext(tctx, query)
if err != nil {
return errors.Annotatef(err, "sql: %s", query)
}
results, err := GetSpecifiedColumnValuesAndClose(rows, "NAME", "ENGINE", "AVG_ROW_LENGTH", "COMMENT")
if err != nil {
return errors.Annotatef(err, "sql: %s", query)
}
for _, oneRow := range results {
table, engine, avgRowLengthStr, comment := oneRow[0], oneRow[1], oneRow[2], oneRow[3]
for _, tbl := range tbls {
if tbl.Name == table {
if avgRowLengthStr != "" {
avgRowLength, err = strconv.ParseUint(avgRowLengthStr, 10, 64)
if err != nil {
return errors.Annotatef(err, "sql: %s", query)
}
} else {
avgRowLength = 0
}
tbl.AvgRowLength = avgRowLength
tableType = TableTypeBase
if engine == "" && (comment == "" || comment == TableTypeViewStr) {
tableType = TableTypeView
} else if engine == "" {
tctx.L().Warn("invalid table without engine found", zap.String("database", schema), zap.String("table", table))
continue

Check warning on line 351 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L320-L351

Added lines #L320 - L351 were not covered by tests
}
tbl.Type = tableType

Check warning on line 353 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L353

Added line #L353 was not covered by tests
}
}
}
}
return nil

Check warning on line 358 in dumpling/export/sql.go

View check run for this annotation

Codecov / codecov/patch

dumpling/export/sql.go#L358

Added line #L358 was not covered by tests
}
}

// ListAllDatabasesTables lists all the databases and tables from the database
// listTableByInfoSchema list tables by table information_schema in MySQL
// listTableByShowTableStatus has better performance than listTableByInfoSchema
Expand Down
31 changes: 31 additions & 0 deletions dumpling/tests/specified_table_view/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh
#
# Copyright 2024 PingCAP, Inc. Licensed under Apache-2.0.

set -eu
cur=$(cd `dirname $0`; pwd)

DB_NAME="specified_table_view"
TABLE_NAME="t"
VIEW_NAME="v"

run_sql "drop database if exists \`$DB_NAME\`;"
run_sql "create database \`$DB_NAME\`;"
run_sql "create table \`$DB_NAME\`.\`$TABLE_NAME\` (a int);"
run_sql "create view \`$DB_NAME\`.\`$VIEW_NAME\` as select * from \`$DB_NAME\`.\`$TABLE_NAME\`;"

set +e
rm -rf "$DUMPLING_OUTPUT_DIR"
run_dumpling --consistency=lock -T="$DB_NAME.$TABLE_NAME,$DB_NAME.$VIEW_NAME" -L ${DUMPLING_OUTPUT_DIR}/dumpling.log
set -e

file_should_exist "$DUMPLING_OUTPUT_DIR/$DB_NAME.$TABLE_NAME-schema.sql"
file_should_exist "$DUMPLING_OUTPUT_DIR/$DB_NAME.$VIEW_NAME-schema-view.sql"

set +e
rm -rf "$DUMPLING_OUTPUT_DIR"
run_dumpling --consistency=lock -T="$DB_NAME.$TABLE_NAME,$DB_NAME.$VIEW_NAME" -L ${DUMPLING_OUTPUT_DIR}/dumpling.log
set -e

file_should_exist "$DUMPLING_OUTPUT_DIR/$DB_NAME.$TABLE_NAME-schema.sql"
file_should_exist "$DUMPLING_OUTPUT_DIR/$DB_NAME.$VIEW_NAME-schema-view.sql"
Loading