This commit is contained in:
dengqichen 2025-11-15 16:30:32 +08:00
parent 55ff56a1a7
commit 8bf5813876

View File

@ -217,35 +217,82 @@ class PG2DMConverter {
*/ */
removeEmptyPartition(sql) { removeEmptyPartition(sql) {
let converted = sql; let converted = sql;
let removedCount = 0;
// 移除空的PARTITION BY子句 // 1. 移除 PARTITION BY LIST (column) 后面没有具体分区的情况
// 格式1: )\nPARTITION BY (\n)\n; // 格式: )\nPARTITION BY LIST (\n "column"\n)\n;
// 格式2: ) PARTITION BY (); const listPattern = /\)\s*PARTITION\s+BY\s+LIST\s*\([^)]+\)\s*;/gi;
const listMatches = converted.match(listPattern);
if (listMatches) {
converted = converted.replace(listPattern, ');');
removedCount += listMatches.length;
this.log(`移除 ${listMatches.length} 个空的PARTITION BY LIST子句`);
}
// 2. 移除 PARTITION BY RANGE (column) 后面没有具体分区的情况
const rangePattern = /\)\s*PARTITION\s+BY\s+RANGE\s*\([^)]+\)\s*;/gi;
const rangeMatches = converted.match(rangePattern);
if (rangeMatches) {
converted = converted.replace(rangePattern, ');');
removedCount += rangeMatches.length;
this.log(`移除 ${rangeMatches.length} 个空的PARTITION BY RANGE子句`);
}
// 3. 移除 PARTITION BY HASH (column) 后面没有具体分区的情况
const hashPattern = /\)\s*PARTITION\s+BY\s+HASH\s*\([^)]+\)\s*;/gi;
const hashMatches = converted.match(hashPattern);
if (hashMatches) {
converted = converted.replace(hashPattern, ');');
removedCount += hashMatches.length;
this.log(`移除 ${hashMatches.length} 个空的PARTITION BY HASH子句`);
}
// 4. 移除空括号的PARTITION BY
converted = converted.replace(/\)\s*PARTITION\s+BY\s+\([^)]*\)\s*;/gi, ');\n'); converted = converted.replace(/\)\s*PARTITION\s+BY\s+\([^)]*\)\s*;/gi, ');\n');
const matches = sql.match(/PARTITION\s+BY\s+\(/gi); if (removedCount > 0) {
if (matches) { this.log(`总共移除 ${removedCount} 个空的PARTITION BY子句`);
this.log(`移除 ${matches.length} 个空的PARTITION BY子句`);
} }
return converted; return converted;
} }
/** /**
* 移除索引注释达梦不支持COMMENT ON INDEX * 移除所有COMMENT语句达梦不支持COMMENT ON语法
*/ */
removeIndexComments(sql) { removeIndexComments(sql) {
let converted = sql; let converted = sql;
let totalRemoved = 0;
// 匹配并移除 COMMENT ON INDEX 语句 // 1. 移除 COMMENT ON COLUMN
// 格式: COMMENT ON INDEX "schema"."index_name" IS '注释内容'; const columnPattern = /COMMENT\s+ON\s+COLUMN\s+"[^"]+"\."[^"]+"\."[^"]+"\s+IS\s+'[^']*'\s*;/gi;
const commentPattern = /COMMENT\s+ON\s+INDEX\s+"[^"]+"\."[^"]+"\s+IS\s+'[^']*'\s*;/gi; const columnMatches = sql.match(columnPattern);
if (columnMatches) {
converted = converted.replace(columnPattern, '');
totalRemoved += columnMatches.length;
this.log(`移除 ${columnMatches.length} 个列注释`);
}
const matches = sql.match(commentPattern); // 2. 移除 COMMENT ON TABLE
if (matches) { const tablePattern = /COMMENT\s+ON\s+TABLE\s+"[^"]+"\."[^"]+"\s+IS\s+'[^']*'\s*;/gi;
this.log(`移除 ${matches.length} 个索引注释达梦不支持COMMENT ON INDEX语法`); const tableMatches = converted.match(tablePattern);
converted = converted.replace(commentPattern, ''); if (tableMatches) {
converted = converted.replace(tablePattern, '');
totalRemoved += tableMatches.length;
this.log(`移除 ${tableMatches.length} 个表注释`);
}
// 3. 移除 COMMENT ON INDEX
const indexPattern = /COMMENT\s+ON\s+INDEX\s+"[^"]+"\."[^"]+"\s+IS\s+'[^']*'\s*;/gi;
const indexMatches = converted.match(indexPattern);
if (indexMatches) {
converted = converted.replace(indexPattern, '');
totalRemoved += indexMatches.length;
this.log(`移除 ${indexMatches.length} 个索引注释`);
}
if (totalRemoved > 0) {
this.log(`总共移除 ${totalRemoved} 个COMMENT语句达梦不支持`);
// 清理可能产生的多余空行 // 清理可能产生的多余空行
converted = converted.replace(/\n\n\n+/g, '\n\n'); converted = converted.replace(/\n\n\n+/g, '\n\n');
} }
@ -253,6 +300,73 @@ class PG2DMConverter {
return converted; return converted;
} }
/**
* 移除分区附加语句达梦不支持ATTACH PARTITION
*/
removeAttachPartition(sql) {
let converted = sql;
// 匹配 ALTER TABLE ... ATTACH PARTITION ... FOR VALUES ...;
const attachPattern = /ALTER\s+TABLE\s+"[^"]+"\."[^"]+"\s+ATTACH\s+PARTITION\s+"[^"]+"\."[^"]+"\s+FOR\s+VALUES[^;]*;/gi;
const matches = sql.match(attachPattern);
if (matches) {
this.log(`移除 ${matches.length} 个ATTACH PARTITION语句达梦不支持`);
converted = converted.replace(attachPattern, '');
// 清理多余空行
converted = converted.replace(/\n\n\n+/g, '\n\n');
}
return converted;
}
/**
* 移除与主键约束同名的唯一索引
* PostgreSQL导出时会同时包含索引和约束但在达梦中会冲突
*/
removeDuplicatePrimaryKeyIndexes(sql) {
let converted = sql;
let removedCount = 0;
// 1. 提取所有主键约束的名称
const pkConstraintPattern = /ADD\s+CONSTRAINT\s+"([^"]+)"\s+PRIMARY\s+KEY/gi;
const constraintNames = new Set();
let match;
while ((match = pkConstraintPattern.exec(sql)) !== null) {
constraintNames.add(match[1]);
}
if (constraintNames.size === 0) {
return converted;
}
// 2. 移除与这些约束同名的UNIQUE INDEX
constraintNames.forEach(constraintName => {
// 匹配: CREATE UNIQUE INDEX "constraint_name" ON ...;
const indexPattern = new RegExp(
`CREATE\\s+UNIQUE\\s+INDEX\\s+"${constraintName}"\\s+ON\\s+[^;]+;`,
'gi'
);
const indexMatches = converted.match(indexPattern);
if (indexMatches) {
converted = converted.replace(indexPattern, '');
removedCount += indexMatches.length;
this.log(`移除与主键约束同名的唯一索引: ${constraintName}`);
}
});
if (removedCount > 0) {
this.log(`总共移除 ${removedCount} 个与主键同名的唯一索引`);
// 清理多余空行
converted = converted.replace(/\n\n\n+/g, '\n\n');
}
return converted;
}
/** /**
* 简化索引语法 * 简化索引语法
*/ */
@ -438,7 +552,15 @@ class PG2DMConverter {
this.log('步骤11: 移除索引注释...'); this.log('步骤11: 移除索引注释...');
converted = this.removeIndexComments(converted); converted = this.removeIndexComments(converted);
// 12. 添加转换说明 // 12. 移除分区附加语句达梦不支持ATTACH PARTITION
this.log('步骤12: 移除分区附加语句...');
converted = this.removeAttachPartition(converted);
// 13. 移除与主键约束同名的唯一索引(避免冲突)
this.log('步骤13: 移除与主键约束同名的唯一索引...');
converted = this.removeDuplicatePrimaryKeyIndexes(converted);
// 14. 添加转换说明
if (config.output.addConversionComment) { if (config.output.addConversionComment) {
converted = this.addConversionHeader(converted, originalFile); converted = this.addConversionHeader(converted, originalFile);
} }