From 3f07dc8e8efad2e6ec51f2dced8edb15b0aabfcb Mon Sep 17 00:00:00 2001 From: smail Date: Tue, 22 Sep 2026 03:58:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=8A=A8=E6=80=81SQL?= =?UTF-8?q?=E6=A0=87=E8=AF=86=E7=AC=A6=E5=AE=89=E5=85=A8=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/services/dbmigration/portable_data.go | 2 ++ backend/services/dbmigration/sql_executor.go | 3 +++ 2 files changed, 5 insertions(+) diff --git a/backend/services/dbmigration/portable_data.go b/backend/services/dbmigration/portable_data.go index eb4c3e5..3d00f01 100644 --- a/backend/services/dbmigration/portable_data.go +++ b/backend/services/dbmigration/portable_data.go @@ -190,6 +190,7 @@ func copyPortableTables(ctx context.Context, source *sql.Conn, target *sql.DB, p } // 只有绑定序列的主键需要推进;日志等文本主键不能参与数值聚合。 if sequence.Valid { + // #nosec G202 -- 表名来自数据库元数据,并通过标识符引用;数据值仍使用参数。 query := "SELECT setval($1::regclass, COALESCE(MAX(id), 1), MAX(id) IS NOT NULL) FROM " + quoted if _, err := transaction.ExecContext(ctx, query, sequence.String); err != nil { return ErrSQLDataVerification @@ -235,6 +236,7 @@ func synchronizeSequences(ctx context.Context, transaction *sql.Tx, plan Plan, s return ErrSQLDataVerification } case config.DatabaseTypePostgreSQL: + // #nosec G202 -- 序列名称来自数据库元数据,并通过 PostgreSQL 标识符引用;数值使用参数。 query := "SELECT setval(pg_get_serial_sequence($1, 'id'), GREATEST(COALESCE(MAX(id), 0), $2), true) FROM " + quotePostgreSQLIdentifier(sequence.Name) if _, err := transaction.ExecContext(ctx, query, sequence.Name, sequence.Seq); err != nil { return ErrSQLDataVerification diff --git a/backend/services/dbmigration/sql_executor.go b/backend/services/dbmigration/sql_executor.go index 6528dd7..620a306 100644 --- a/backend/services/dbmigration/sql_executor.go +++ b/backend/services/dbmigration/sql_executor.go @@ -236,6 +236,7 @@ func (c *SQLCopier) copyMySQL(ctx context.Context, sourceDB, adminDB *sql.DB, so } }() + // #nosec G202 -- 数据库名称来自已校验配置,并通过 MySQL 标识符引用。 rows, err := sourceDB.QueryContext(ctx, "SHOW FULL TABLES FROM "+quoteMySQLIdentifier(sourceName)) if err != nil { return fmt.Errorf("list mysql tables: %w", err) @@ -275,6 +276,7 @@ func (c *SQLCopier) copyMySQL(ctx context.Context, sourceDB, adminDB *sql.DB, so } sourceTable := quoteMySQLIdentifier(sourceName) + "." + quoteMySQLIdentifier(tableName) targetTable := quoteMySQLIdentifier(targetName) + "." + quoteMySQLIdentifier(tableName) + // #nosec G202 -- 源表和目标表均来自数据库元数据并通过 MySQL 标识符引用。 if _, err := adminDB.ExecContext(ctx, "INSERT INTO "+targetTable+" SELECT * FROM "+sourceTable); err != nil { return fmt.Errorf("copy mysql table data: %w", err) } @@ -362,6 +364,7 @@ func (c *SQLCopier) copyMySQLForeignKeys(ctx context.Context, database *sql.DB, } columns := quoteMySQLIdentifiers(foreignKey.columns) referencedColumns := quoteMySQLIdentifiers(foreignKey.referencedColumns) + // #nosec G202 -- 外键标识符统一引用,更新和删除规则已通过白名单校验。 query := "ALTER TABLE " + quoteMySQLIdentifier(targetName) + "." + quoteMySQLIdentifier(foreignKey.tableName) + " ADD CONSTRAINT " + quoteMySQLIdentifier(foreignKey.constraintName) + " FOREIGN KEY (" + strings.Join(columns, ", ") + ") REFERENCES " + quoteMySQLIdentifier(referencedSchema) + "." + quoteMySQLIdentifier(foreignKey.referencedTable) + " (" + strings.Join(referencedColumns, ", ") + ") ON UPDATE " + foreignKey.updateRule + " ON DELETE " + foreignKey.deleteRule if _, err := database.ExecContext(ctx, query); err != nil { return fmt.Errorf("copy mysql foreign key: %w", err)