This commit is contained in:
dengqichen 2025-11-15 15:34:19 +08:00
parent 7e6e46bb4a
commit 20bff2b6cd
2 changed files with 29 additions and 11 deletions

View File

@ -13,7 +13,7 @@ module.exports = {
'timestamp': 'TIMESTAMP',
'timestamptz': 'TIMESTAMP', // PostgreSQL timestamp with time zone
'bool': 'BIT',
'text': 'TEXT',
'text': 'VARCHAR(8000)', // 达梦的TEXT是CLOB不能建索引改用VARCHAR
'bytea': 'BLOB',
'float8': 'DOUBLE', // PostgreSQL double precision
'float4': 'REAL', // PostgreSQL real/float

View File

@ -44,7 +44,7 @@ class PG2DMConverter {
let converted = sql;
// 1. 转换基本类型(包括浮点类型和时间戳类型)
const typePattern = /\b(int8|int4|int2|numeric|bool|float8|float4|float|timestamptz)\b/gi;
const typePattern = /\b(int8|int4|int2|numeric|bool|float8|float4|float|timestamptz|text)\b/gi;
converted = converted.replace(typePattern, (match) => {
const lowerMatch = match.toLowerCase();
@ -63,6 +63,27 @@ class PG2DMConverter {
return `TIMESTAMP`;
});
// 3. 移除时区子句
// PostgreSQL: TIMESTAMP without time zone / TIMESTAMP with time zone
// 达梦: TIMESTAMP (不支持时区子句)
converted = converted.replace(/TIMESTAMP\s+(without|with)\s+time\s+zone/gi, 'TIMESTAMP');
const timezoneMatches = sql.match(/TIMESTAMP\s+(without|with)\s+time\s+zone/gi);
if (timezoneMatches) {
this.log(`移除 ${timezoneMatches.length} 个TIMESTAMP时区子句`);
}
// 4. 修正DECIMAL精度超出范围
// 达梦DECIMAL最大精度38位PostgreSQL可以到1000位
converted = converted.replace(/DECIMAL\s*\((\d+)\s*,\s*(\d+)\)/gi, (match, precision, scale) => {
const p = parseInt(precision);
const s = parseInt(scale);
if (p > 38) {
this.warn(`DECIMAL(${p},${s}) 精度超出达梦限制(最大38)已调整为DECIMAL(38,${s})`);
return `DECIMAL(38,${s})`;
}
return match;
});
return converted;
}
@ -177,17 +198,14 @@ class PG2DMConverter {
removeTypeQuotes(sql) {
let converted = sql;
// 先统一小写的text类型为TEXT避免和"text_ops"操作符混淆)
converted = converted.replace(/\s+text\s+/gi, ' TEXT ');
converted = converted.replace(/\s+text([,\n\r])/gi, ' TEXT$1');
// 移除引号中的数据类型(达梦不需要给类型加引号)
// 必须在独立的步骤中处理,确保不会误伤列名
// 匹配模式:前面有空格,后面有空格或逗号
converted = converted.replace(/\s"(BIGINT|INT|SMALLINT|TINYINT|DECIMAL|NUMERIC|VARCHAR|CHAR|TEXT|DATE|TIME|TIMESTAMP|BIT|BOOLEAN|BOOL|BLOB|CLOB)"\s/gi, ' $1 ');
// 1. 先处理带括号的类型VARCHAR(8000), DECIMAL(20,6)等
converted = converted.replace(/\s"(VARCHAR|CHAR|DECIMAL|NUMERIC)\s*\([^)]+\)"\s/gi, ' $1 ');
converted = converted.replace(/\s"(VARCHAR|CHAR|DECIMAL|NUMERIC)\s*\([^)]+\)"([,\n\r])/gi, ' $1$2');
// 处理行尾的类型(后面紧跟换行或逗号)
converted = converted.replace(/\s"(BIGINT|INT|SMALLINT|TINYINT|DECIMAL|NUMERIC|VARCHAR|CHAR|TEXT|DATE|TIME|TIMESTAMP|BIT|BOOLEAN|BOOL|BLOB|CLOB)"([,\n\r])/gi, ' $1$2');
// 2. 再处理简单类型
converted = converted.replace(/\s"(BIGINT|INT|SMALLINT|TINYINT|VARCHAR|CHAR|TEXT|DATE|TIME|TIMESTAMP|BIT|BOOLEAN|BOOL|BLOB|CLOB)"\s/gi, ' $1 ');
converted = converted.replace(/\s"(BIGINT|INT|SMALLINT|TINYINT|VARCHAR|CHAR|TEXT|DATE|TIME|TIMESTAMP|BIT|BOOLEAN|BOOL|BLOB|CLOB)"([,\n\r])/gi, ' $1$2');
this.log('移除数据类型引号');