Commit 4401c703ef59dc68d97530172d4845835eb9de43

Authored by dhb52
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&quot;&quot;&quot; @@ -571,14 +644,18 @@ GO&quot;&quot;&quot;
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