Commit 4401c703ef59dc68d97530172d4845835eb9de43
1 parent
3140ec89
feat: 增加 UNIQUE KEY 支持
Showing
1 changed file
with
142 additions
and
44 deletions
sql/tools/convertor.py
| @@ -4,6 +4,14 @@ | @@ -4,6 +4,14 @@ | ||
| 4 | Author: dhb52 (https://gitee.com/dhb52) | 4 | Author: dhb52 (https://gitee.com/dhb52) |
| 5 | 5 | ||
| 6 | pip install simple-ddl-parser | 6 | pip install simple-ddl-parser |
| 7 | + | ||
| 8 | +or with uv | ||
| 9 | +uv run --with simple-ddl-parser convertor.py postgres > ../postgresql/ruoyi-vue-pro.sql 239ms 四 5/22 21:03:16 2025 | ||
| 10 | +uv run --with simple-ddl-parser convertor.py sqlserver > ../sqlserver/ruoyi-vue-pro.sql | ||
| 11 | +uv run --with simple-ddl-parser convertor.py kingbase > ../kingbase/ruoyi-vue-pro.sql | ||
| 12 | +uv run --with simple-ddl-parser convertor.py opengauss > ../opengauss/ruoyi-vue-pro.sql | ||
| 13 | +uv run --with simple-ddl-parser convertor.py oracle > ../oracle/ruoyi-vue-pro.sql | ||
| 14 | +uv run --with simple-ddl-parser convertor.py dm8 > ../dm/ruoyi-vue-pro-dm8.sql | ||
| 7 | """ | 15 | """ |
| 8 | 16 | ||
| 9 | import argparse | 17 | import argparse |
| @@ -38,6 +46,7 @@ def load_and_clean(sql_file: str) -> str: | @@ -38,6 +46,7 @@ def load_and_clean(sql_file: str) -> str: | ||
| 38 | str: 清理后的sql文件内容 | 46 | str: 清理后的sql文件内容 |
| 39 | """ | 47 | """ |
| 40 | REPLACE_PAIR_LIST = ( | 48 | REPLACE_PAIR_LIST = ( |
| 49 | + (")\nVALUES ", ") VALUES "), | ||
| 41 | (" CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ", " "), | 50 | (" CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ", " "), |
| 42 | (" KEY `", " INDEX `"), | 51 | (" KEY `", " INDEX `"), |
| 43 | ("UNIQUE INDEX", "UNIQUE KEY"), | 52 | ("UNIQUE INDEX", "UNIQUE KEY"), |
| @@ -45,7 +54,7 @@ def load_and_clean(sql_file: str) -> str: | @@ -45,7 +54,7 @@ def load_and_clean(sql_file: str) -> str: | ||
| 45 | ("b'1'", "'1'"), | 54 | ("b'1'", "'1'"), |
| 46 | ) | 55 | ) |
| 47 | 56 | ||
| 48 | - content = open(sql_file).read() | 57 | + content = open(sql_file, encoding="utf-8").read() |
| 49 | for replace_pair in REPLACE_PAIR_LIST: | 58 | for replace_pair in REPLACE_PAIR_LIST: |
| 50 | content = content.replace(*replace_pair) | 59 | content = content.replace(*replace_pair) |
| 51 | content = re.sub(r"ENGINE.*COMMENT", "COMMENT", content) | 60 | content = re.sub(r"ENGINE.*COMMENT", "COMMENT", content) |
| @@ -110,12 +119,11 @@ class Convertor(ABC): | @@ -110,12 +119,11 @@ class Convertor(ABC): | ||
| 110 | pass | 119 | pass |
| 111 | 120 | ||
| 112 | @abstractmethod | 121 | @abstractmethod |
| 113 | - def gen_comment(self, table_sql: str, table_name: str) -> str: | 122 | + def gen_comment(self, table_ddl: Dict) -> str: |
| 114 | """生成字段/表注释 | 123 | """生成字段/表注释 |
| 115 | 124 | ||
| 116 | Args: | 125 | Args: |
| 117 | - table_sql (str): 原始表SQL | ||
| 118 | - table_name (str): 表名 | 126 | + table_ddl (Dict): 表DDL |
| 119 | 127 | ||
| 120 | Returns: | 128 | Returns: |
| 121 | str: 生成脚本 | 129 | str: 生成脚本 |
| @@ -123,6 +131,17 @@ class Convertor(ABC): | @@ -123,6 +131,17 @@ class Convertor(ABC): | ||
| 123 | pass | 131 | pass |
| 124 | 132 | ||
| 125 | @abstractmethod | 133 | @abstractmethod |
| 134 | + def gen_uk(self, table_ddl: Dict) -> str: | ||
| 135 | + """生成 | ||
| 136 | + | ||
| 137 | + Args: | ||
| 138 | + table_ddl (Dict): 表DDL | ||
| 139 | + | ||
| 140 | + Returns: | ||
| 141 | + str: 生成脚本 | ||
| 142 | + """ | ||
| 143 | + | ||
| 144 | + @abstractmethod | ||
| 126 | def gen_insert(self, table_name: str) -> str: | 145 | def gen_insert(self, table_name: str) -> str: |
| 127 | """生成 insert 语句块 | 146 | """生成 insert 语句块 |
| 128 | 147 | ||
| @@ -179,6 +198,16 @@ class Convertor(ABC): | @@ -179,6 +198,16 @@ class Convertor(ABC): | ||
| 179 | yield f"CREATE INDEX idx_{table_name}_{no:02d} ON {table_name} ({columns})" | 198 | yield f"CREATE INDEX idx_{table_name}_{no:02d} ON {table_name} ({columns})" |
| 180 | 199 | ||
| 181 | @staticmethod | 200 | @staticmethod |
| 201 | + def unique_index(ddl: Dict) -> Generator: | ||
| 202 | + if "constraints" in ddl and "uniques" in ddl["constraints"]: | ||
| 203 | + uk_list = ddl["constraints"]["uniques"] | ||
| 204 | + for uk in uk_list: | ||
| 205 | + table_name = ddl["table_name"] | ||
| 206 | + uk_name = uk["constraint_name"] | ||
| 207 | + uk_columns = uk["columns"] | ||
| 208 | + yield table_name, uk_name, uk_columns | ||
| 209 | + | ||
| 210 | + @staticmethod | ||
| 182 | def filed_comments(table_sql: str) -> Generator: | 211 | def filed_comments(table_sql: str) -> Generator: |
| 183 | for line in table_sql.split("\n"): | 212 | for line in table_sql.split("\n"): |
| 184 | match = re.match(r"^`([^`]+)`.* COMMENT '([^']+)'", line.strip()) | 213 | match = re.match(r"^`([^`]+)`.* COMMENT '([^']+)'", line.strip()) |
| @@ -188,7 +217,7 @@ class Convertor(ABC): | @@ -188,7 +217,7 @@ class Convertor(ABC): | ||
| 188 | yield field, comment_string | 217 | yield field, comment_string |
| 189 | 218 | ||
| 190 | def table_comment(self, table_sql: str) -> str: | 219 | def table_comment(self, table_sql: str) -> str: |
| 191 | - match = re.search(r"COMMENT \= '([^']+)';", table_sql) | 220 | + match = re.search(r"COMMENT \='([^']+)';", table_sql) |
| 192 | return match.group(1) if match else None | 221 | return match.group(1) if match else None |
| 193 | 222 | ||
| 194 | def print(self): | 223 | def print(self): |
| @@ -226,11 +255,21 @@ class Convertor(ABC): | @@ -226,11 +255,21 @@ class Convertor(ABC): | ||
| 226 | if table_name.lower().startswith("qrtz"): | 255 | if table_name.lower().startswith("qrtz"): |
| 227 | continue | 256 | continue |
| 228 | 257 | ||
| 229 | - # 为每个表生成个5个基本部分 | 258 | + # 解析注释 |
| 259 | + for column in table_ddl["columns"]: | ||
| 260 | + column["comment"] = bytes(column["comment"], "utf-8").decode( | ||
| 261 | + "unicode_escape" | ||
| 262 | + )[1:-1] | ||
| 263 | + table_ddl["comment"] = bytes(table_ddl["comment"], "utf-8").decode( | ||
| 264 | + "unicode_escape" | ||
| 265 | + )[1:-1] | ||
| 266 | + | ||
| 267 | + # 为每个表生成个6个基本部分 | ||
| 230 | create = self.gen_create(table_ddl) | 268 | create = self.gen_create(table_ddl) |
| 231 | pk = self.gen_pk(table_name) | 269 | pk = self.gen_pk(table_name) |
| 270 | + uk = self.gen_uk(table_ddl) | ||
| 232 | index = self.gen_index(table_ddl) | 271 | index = self.gen_index(table_ddl) |
| 233 | - comment = self.gen_comment(table_sql, table_name) | 272 | + comment = self.gen_comment(table_ddl) |
| 234 | inserts = self.gen_insert(table_name) | 273 | inserts = self.gen_insert(table_name) |
| 235 | 274 | ||
| 236 | # 组合当前表的DDL脚本 | 275 | # 组合当前表的DDL脚本 |
| @@ -238,6 +277,8 @@ class Convertor(ABC): | @@ -238,6 +277,8 @@ class Convertor(ABC): | ||
| 238 | 277 | ||
| 239 | {pk} | 278 | {pk} |
| 240 | 279 | ||
| 280 | +{uk} | ||
| 281 | + | ||
| 241 | {index} | 282 | {index} |
| 242 | 283 | ||
| 243 | {comment} | 284 | {comment} |
| @@ -267,17 +308,19 @@ class PostgreSQLConvertor(Convertor): | @@ -267,17 +308,19 @@ class PostgreSQLConvertor(Convertor): | ||
| 267 | 308 | ||
| 268 | if type == "varchar": | 309 | if type == "varchar": |
| 269 | return f"varchar({size})" | 310 | return f"varchar({size})" |
| 270 | - if type == "int": | 311 | + if type in ("int", "int unsigned"): |
| 271 | return "int4" | 312 | return "int4" |
| 272 | - if type == "bigint" or type == "bigint unsigned": | 313 | + if type in ("bigint", "bigint unsigned"): |
| 273 | return "int8" | 314 | return "int8" |
| 274 | if type == "datetime": | 315 | if type == "datetime": |
| 275 | return "timestamp" | 316 | return "timestamp" |
| 317 | + if type == "timestamp": | ||
| 318 | + return f"timestamp({size})" | ||
| 276 | if type == "bit": | 319 | if type == "bit": |
| 277 | return "bool" | 320 | return "bool" |
| 278 | if type in ("tinyint", "smallint"): | 321 | if type in ("tinyint", "smallint"): |
| 279 | return "int2" | 322 | return "int2" |
| 280 | - if type == "text": | 323 | + if type in ("text", "longtext"): |
| 281 | return "text" | 324 | return "text" |
| 282 | if type in ("blob", "mediumblob"): | 325 | if type in ("blob", "mediumblob"): |
| 283 | return "bytea" | 326 | return "bytea" |
| @@ -316,18 +359,22 @@ CREATE TABLE {table_name} ( | @@ -316,18 +359,22 @@ CREATE TABLE {table_name} ( | ||
| 316 | def gen_index(self, ddl: Dict) -> str: | 359 | def gen_index(self, ddl: Dict) -> str: |
| 317 | return "\n".join(f"{script};" for script in self.index(ddl)) | 360 | return "\n".join(f"{script};" for script in self.index(ddl)) |
| 318 | 361 | ||
| 319 | - def gen_comment(self, table_sql: str, table_name: str) -> str: | 362 | + def gen_comment(self, table_ddl: Dict) -> str: |
| 320 | """生成字段及表的注释""" | 363 | """生成字段及表的注释""" |
| 321 | 364 | ||
| 322 | script = "" | 365 | script = "" |
| 323 | - for field, comment_string in self.filed_comments(table_sql): | 366 | + for column in table_ddl["columns"]: |
| 367 | + table_comment = column["comment"] | ||
| 324 | script += ( | 368 | script += ( |
| 325 | - f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n" | 369 | + f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';" |
| 370 | + + "\n" | ||
| 326 | ) | 371 | ) |
| 327 | 372 | ||
| 328 | - table_comment = self.table_comment(table_sql) | 373 | + table_comment = table_ddl["comment"] |
| 329 | if table_comment: | 374 | if table_comment: |
| 330 | - script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n" | 375 | + script += ( |
| 376 | + f"COMMENT ON TABLE {table_ddl['table_name']} IS '{table_comment}';\n" | ||
| 377 | + ) | ||
| 331 | 378 | ||
| 332 | return script | 379 | return script |
| 333 | 380 | ||
| @@ -335,6 +382,15 @@ CREATE TABLE {table_name} ( | @@ -335,6 +382,15 @@ CREATE TABLE {table_name} ( | ||
| 335 | """生成主键定义""" | 382 | """生成主键定义""" |
| 336 | return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n" | 383 | return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n" |
| 337 | 384 | ||
| 385 | + def gen_uk(self, table_ddl: Dict) -> str: | ||
| 386 | + script = "" | ||
| 387 | + uk_list = list(Convertor.unique_index(table_ddl)) | ||
| 388 | + for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1): | ||
| 389 | + uk_name = f"uk_{table_name}_{idx:02d}" | ||
| 390 | + script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)});\n" | ||
| 391 | + | ||
| 392 | + return script | ||
| 393 | + | ||
| 338 | def gen_insert(self, table_name: str) -> str: | 394 | def gen_insert(self, table_name: str) -> str: |
| 339 | """生成 insert 语句,以及根据最后的 insert id+1 生成 Sequence""" | 395 | """生成 insert 语句,以及根据最后的 insert id+1 生成 Sequence""" |
| 340 | 396 | ||
| @@ -393,17 +449,19 @@ class OracleConvertor(Convertor): | @@ -393,17 +449,19 @@ class OracleConvertor(Convertor): | ||
| 393 | 449 | ||
| 394 | if type == "varchar": | 450 | if type == "varchar": |
| 395 | return f"varchar2({size if size < 4000 else 4000})" | 451 | return f"varchar2({size if size < 4000 else 4000})" |
| 396 | - if type == "int": | 452 | + if type in ("int", "int unsigned"): |
| 397 | return "number" | 453 | return "number" |
| 398 | if type == "bigint" or type == "bigint unsigned": | 454 | if type == "bigint" or type == "bigint unsigned": |
| 399 | return "number" | 455 | return "number" |
| 400 | if type == "datetime": | 456 | if type == "datetime": |
| 401 | return "date" | 457 | return "date" |
| 458 | + if type == "timestamp": | ||
| 459 | + return f"timestamp({size})" | ||
| 402 | if type == "bit": | 460 | if type == "bit": |
| 403 | return "number(1,0)" | 461 | return "number(1,0)" |
| 404 | if type in ("tinyint", "smallint"): | 462 | if type in ("tinyint", "smallint"): |
| 405 | return "smallint" | 463 | return "smallint" |
| 406 | - if type == "text": | 464 | + if type in ("text", "longtext"): |
| 407 | return "clob" | 465 | return "clob" |
| 408 | if type in ("blob", "mediumblob"): | 466 | if type in ("blob", "mediumblob"): |
| 409 | return "blob" | 467 | return "blob" |
| @@ -423,6 +481,8 @@ class OracleConvertor(Convertor): | @@ -423,6 +481,8 @@ class OracleConvertor(Convertor): | ||
| 423 | type = col["type"].lower() | 481 | type = col["type"].lower() |
| 424 | full_type = self.translate_type(type, col["size"]) | 482 | full_type = self.translate_type(type, col["size"]) |
| 425 | nullable = "NULL" if col["nullable"] else "NOT NULL" | 483 | nullable = "NULL" if col["nullable"] else "NOT NULL" |
| 484 | + # Oracle的 INSERT '' 不能通过NOT NULL校验,因此对文字类型字段覆写为 NULL | ||
| 485 | + nullable = "NULL" if type in ("varchar", "text", "longtext") else nullable | ||
| 426 | default = f"DEFAULT {col['default']}" if col["default"] is not None else "" | 486 | default = f"DEFAULT {col['default']}" if col["default"] is not None else "" |
| 427 | # Oracle 中 size 不能作为字段名 | 487 | # Oracle 中 size 不能作为字段名 |
| 428 | field_name = '"size"' if name == "size" else name | 488 | field_name = '"size"' if name == "size" else name |
| @@ -447,16 +507,20 @@ CREATE TABLE {table_name} ( | @@ -447,16 +507,20 @@ CREATE TABLE {table_name} ( | ||
| 447 | def gen_index(self, ddl: Dict) -> str: | 507 | def gen_index(self, ddl: Dict) -> str: |
| 448 | return "\n".join(f"{script};" for script in self.index(ddl)) | 508 | return "\n".join(f"{script};" for script in self.index(ddl)) |
| 449 | 509 | ||
| 450 | - def gen_comment(self, table_sql: str, table_name: str) -> str: | 510 | + def gen_comment(self, table_ddl: Dict) -> str: |
| 451 | script = "" | 511 | script = "" |
| 452 | - for field, comment_string in self.filed_comments(table_sql): | 512 | + for column in table_ddl["columns"]: |
| 513 | + table_comment = column["comment"] | ||
| 453 | script += ( | 514 | script += ( |
| 454 | - f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n" | 515 | + f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';" |
| 516 | + + "\n" | ||
| 455 | ) | 517 | ) |
| 456 | 518 | ||
| 457 | - table_comment = self.table_comment(table_sql) | 519 | + table_comment = table_ddl["comment"] |
| 458 | if table_comment: | 520 | if table_comment: |
| 459 | - script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n" | 521 | + script += ( |
| 522 | + f"COMMENT ON TABLE {table_ddl['table_name']} IS '{table_comment}';\n" | ||
| 523 | + ) | ||
| 460 | 524 | ||
| 461 | return script | 525 | return script |
| 462 | 526 | ||
| @@ -464,6 +528,15 @@ CREATE TABLE {table_name} ( | @@ -464,6 +528,15 @@ CREATE TABLE {table_name} ( | ||
| 464 | """生成主键定义""" | 528 | """生成主键定义""" |
| 465 | return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n" | 529 | return f"ALTER TABLE {table_name} ADD CONSTRAINT pk_{table_name} PRIMARY KEY (id);\n" |
| 466 | 530 | ||
| 531 | + def gen_uk(self, table_ddl: Dict) -> str: | ||
| 532 | + script = "" | ||
| 533 | + uk_list = list(Convertor.unique_index(table_ddl)) | ||
| 534 | + for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1): | ||
| 535 | + uk_name = f"uk_{table_name}_{idx:02d}" | ||
| 536 | + script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)});\n" | ||
| 537 | + | ||
| 538 | + return script | ||
| 539 | + | ||
| 467 | def gen_index(self, ddl: Dict) -> str: | 540 | def gen_index(self, ddl: Dict) -> str: |
| 468 | return "\n".join(f"{script};" for script in self.index(ddl)) | 541 | return "\n".join(f"{script};" for script in self.index(ddl)) |
| 469 | 542 | ||
| @@ -521,17 +594,17 @@ class SQLServerConvertor(Convertor): | @@ -521,17 +594,17 @@ class SQLServerConvertor(Convertor): | ||
| 521 | 594 | ||
| 522 | if type == "varchar": | 595 | if type == "varchar": |
| 523 | return f"nvarchar({size if size < 4000 else 4000})" | 596 | return f"nvarchar({size if size < 4000 else 4000})" |
| 524 | - if type == "int": | 597 | + if type in ("int", "int unsigned"): |
| 525 | return "int" | 598 | return "int" |
| 526 | - if type == "bigint" or type == "bigint unsigned": | 599 | + if type in ("bigint", "bigint unsigned"): |
| 527 | return "bigint" | 600 | return "bigint" |
| 528 | - if type == "datetime": | 601 | + if type in ("datetime", "timestamp"): |
| 529 | return "datetime2" | 602 | return "datetime2" |
| 530 | if type == "bit": | 603 | if type == "bit": |
| 531 | return "varchar(1)" | 604 | return "varchar(1)" |
| 532 | if type in ("tinyint", "smallint"): | 605 | if type in ("tinyint", "smallint"): |
| 533 | return "tinyint" | 606 | return "tinyint" |
| 534 | - if type == "text": | 607 | + if type in ("text", "longtext"): |
| 535 | return "nvarchar(max)" | 608 | return "nvarchar(max)" |
| 536 | if type in ("blob", "mediumblob"): | 609 | if type in ("blob", "mediumblob"): |
| 537 | return "varbinary(max)" | 610 | return "varbinary(max)" |
| @@ -571,14 +644,18 @@ GO""" | @@ -571,14 +644,18 @@ GO""" | ||
| 571 | 644 | ||
| 572 | return script | 645 | return script |
| 573 | 646 | ||
| 574 | - def gen_comment(self, table_sql: str, table_name: str) -> str: | 647 | + def gen_comment(self, table_ddl: Dict) -> str: |
| 575 | """生成字段及表的注释""" | 648 | """生成字段及表的注释""" |
| 576 | 649 | ||
| 577 | script = "" | 650 | script = "" |
| 651 | + table_name = table_ddl["table_name"] | ||
| 652 | + | ||
| 653 | + for column in table_ddl["columns"]: | ||
| 654 | + column_comment = column["comment"] | ||
| 655 | + field = column["name"] | ||
| 578 | 656 | ||
| 579 | - for field, comment_string in self.filed_comments(table_sql): | ||
| 580 | script += f"""EXEC sp_addextendedproperty | 657 | script += f"""EXEC sp_addextendedproperty |
| 581 | - 'MS_Description', N'{comment_string}', | 658 | + 'MS_Description', N'{column_comment}', |
| 582 | 'SCHEMA', N'dbo', | 659 | 'SCHEMA', N'dbo', |
| 583 | 'TABLE', N'{table_name}', | 660 | 'TABLE', N'{table_name}', |
| 584 | 'COLUMN', N'{field}' | 661 | 'COLUMN', N'{field}' |
| @@ -586,7 +663,7 @@ GO | @@ -586,7 +663,7 @@ GO | ||
| 586 | 663 | ||
| 587 | """ | 664 | """ |
| 588 | 665 | ||
| 589 | - table_comment = self.table_comment(table_sql) | 666 | + table_comment = table_ddl["comment"] |
| 590 | if table_comment: | 667 | if table_comment: |
| 591 | script += f"""EXEC sp_addextendedproperty | 668 | script += f"""EXEC sp_addextendedproperty |
| 592 | 'MS_Description', N'{table_comment}', | 669 | 'MS_Description', N'{table_comment}', |
| @@ -601,6 +678,15 @@ GO | @@ -601,6 +678,15 @@ GO | ||
| 601 | """生成主键定义""" | 678 | """生成主键定义""" |
| 602 | return "" | 679 | return "" |
| 603 | 680 | ||
| 681 | + def gen_uk(self, table_ddl: Dict) -> str: | ||
| 682 | + script = "" | ||
| 683 | + uk_list = list(Convertor.unique_index(table_ddl)) | ||
| 684 | + for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1): | ||
| 685 | + uk_name = f"uk_{table_name}_{idx:02d}" | ||
| 686 | + script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)})\nGO" | ||
| 687 | + | ||
| 688 | + return script | ||
| 689 | + | ||
| 604 | def gen_index(self, ddl: Dict) -> str: | 690 | def gen_index(self, ddl: Dict) -> str: |
| 605 | """生成 index""" | 691 | """生成 index""" |
| 606 | return "\n".join(f"{script}\nGO" for script in self.index(ddl)) | 692 | return "\n".join(f"{script}\nGO" for script in self.index(ddl)) |
| @@ -674,22 +760,22 @@ class DM8Convertor(Convertor): | @@ -674,22 +760,22 @@ class DM8Convertor(Convertor): | ||
| 674 | 760 | ||
| 675 | if type == "varchar": | 761 | if type == "varchar": |
| 676 | return f"varchar({size})" | 762 | return f"varchar({size})" |
| 677 | - if type == "int": | 763 | + if type in ("int", "int unsigned"): |
| 678 | return "int" | 764 | return "int" |
| 679 | - if type == "bigint" or type == "bigint unsigned": | 765 | + if type in ("bigint", "bigint unsigned"): |
| 680 | return "bigint" | 766 | return "bigint" |
| 681 | if type == "datetime": | 767 | if type == "datetime": |
| 682 | return "datetime" | 768 | return "datetime" |
| 769 | + if type == "timestamp": | ||
| 770 | + return f"timestamp({size})" | ||
| 683 | if type == "bit": | 771 | if type == "bit": |
| 684 | return "bit" | 772 | return "bit" |
| 685 | if type in ("tinyint", "smallint"): | 773 | if type in ("tinyint", "smallint"): |
| 686 | return "smallint" | 774 | return "smallint" |
| 687 | - if type == "text": | 775 | + if type in ("text", "longtext"): |
| 688 | return "text" | 776 | return "text" |
| 689 | - if type == "blob": | 777 | + if type in ("blob", "mediumblob"): |
| 690 | return "blob" | 778 | return "blob" |
| 691 | - if type == "mediumblob": | ||
| 692 | - return "varchar(10240)" | ||
| 693 | if type == "decimal": | 779 | if type == "decimal": |
| 694 | return ( | 780 | return ( |
| 695 | f"decimal({','.join(str(s) for s in size)})" if len(size) else "decimal" | 781 | f"decimal({','.join(str(s) for s in size)})" if len(size) else "decimal" |
| @@ -724,19 +810,20 @@ CREATE TABLE {table_name} ( | @@ -724,19 +810,20 @@ CREATE TABLE {table_name} ( | ||
| 724 | 810 | ||
| 725 | return script | 811 | return script |
| 726 | 812 | ||
| 727 | - def gen_index(self, ddl: Dict) -> str: | ||
| 728 | - return "\n".join(f"{script};" for script in self.index(ddl)) | ||
| 729 | - | ||
| 730 | - def gen_comment(self, table_sql: str, table_name: str) -> str: | 813 | + def gen_comment(self, table_ddl: Dict) -> str: |
| 731 | script = "" | 814 | script = "" |
| 732 | - for field, comment_string in self.filed_comments(table_sql): | 815 | + for column in table_ddl["columns"]: |
| 816 | + table_comment = column["comment"] | ||
| 733 | script += ( | 817 | script += ( |
| 734 | - f"COMMENT ON COLUMN {table_name}.{field} IS '{comment_string}';" + "\n" | 818 | + f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';" |
| 819 | + + "\n" | ||
| 735 | ) | 820 | ) |
| 736 | 821 | ||
| 737 | - table_comment = self.table_comment(table_sql) | 822 | + table_comment = table_ddl["comment"] |
| 738 | if table_comment: | 823 | if table_comment: |
| 739 | - script += f"COMMENT ON TABLE {table_name} IS '{table_comment}';\n" | 824 | + script += ( |
| 825 | + f"COMMENT ON TABLE {table_ddl['table_name']} IS '{table_comment}';\n" | ||
| 826 | + ) | ||
| 740 | 827 | ||
| 741 | return script | 828 | return script |
| 742 | 829 | ||
| @@ -744,6 +831,15 @@ CREATE TABLE {table_name} ( | @@ -744,6 +831,15 @@ CREATE TABLE {table_name} ( | ||
| 744 | """生成主键定义""" | 831 | """生成主键定义""" |
| 745 | return "" | 832 | return "" |
| 746 | 833 | ||
| 834 | + def gen_uk(self, table_ddl: Dict) -> str: | ||
| 835 | + script = "" | ||
| 836 | + uk_list = list(Convertor.unique_index(table_ddl)) | ||
| 837 | + for idx, (table_name, _, uk_columns) in enumerate(uk_list, 1): | ||
| 838 | + uk_name = f"uk_{table_name}_{idx:02d}" | ||
| 839 | + script += f"CREATE UNIQUE INDEX {uk_name} ON {table_name} ({', '.join(uk_columns)});\n" | ||
| 840 | + | ||
| 841 | + return script | ||
| 842 | + | ||
| 747 | def gen_index(self, ddl: Dict) -> str: | 843 | def gen_index(self, ddl: Dict) -> str: |
| 748 | return "\n".join(f"{script};" for script in self.index(ddl)) | 844 | return "\n".join(f"{script};" for script in self.index(ddl)) |
| 749 | 845 | ||
| @@ -784,6 +880,8 @@ class KingbaseConvertor(PostgreSQLConvertor): | @@ -784,6 +880,8 @@ class KingbaseConvertor(PostgreSQLConvertor): | ||
| 784 | type = col["type"].lower() | 880 | type = col["type"].lower() |
| 785 | full_type = self.translate_type(type, col["size"]) | 881 | full_type = self.translate_type(type, col["size"]) |
| 786 | nullable = "NULL" if col["nullable"] else "NOT NULL" | 882 | nullable = "NULL" if col["nullable"] else "NOT NULL" |
| 883 | + if full_type == "text": | ||
| 884 | + nullable = "NULL" | ||
| 787 | default = f"DEFAULT {col['default']}" if col["default"] is not None else "" | 885 | default = f"DEFAULT {col['default']}" if col["default"] is not None else "" |
| 788 | return f"{name} {full_type} {nullable} {default}" | 886 | return f"{name} {full_type} {nullable} {default}" |
| 789 | 887 |