You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

142 line
4.3 KiB

  1. import frappe
  2. from frappe import _
  3. from frappe.utils import cint, flt
  4. from frappe.database.schema import DBTable, get_definition
  5. class PostgresTable(DBTable):
  6. def create(self):
  7. add_text = ''
  8. # columns
  9. column_defs = self.get_column_definitions()
  10. if column_defs: add_text += ',\n'.join(column_defs)
  11. # TODO: set docstatus length
  12. # create table
  13. frappe.db.sql("""create table `%s` (
  14. name varchar({varchar_len}) not null primary key,
  15. creation timestamp(6),
  16. modified timestamp(6),
  17. modified_by varchar({varchar_len}),
  18. owner varchar({varchar_len}),
  19. docstatus smallint not null default '0',
  20. parent varchar({varchar_len}),
  21. parentfield varchar({varchar_len}),
  22. parenttype varchar({varchar_len}),
  23. idx bigint not null default '0',
  24. %s)""".format(varchar_len=frappe.db.VARCHAR_LEN) % (self.table_name, add_text))
  25. self.create_indexes()
  26. frappe.db.commit()
  27. def create_indexes(self):
  28. create_index_query = ""
  29. for key, col in self.columns.items():
  30. if (col.set_index
  31. and col.fieldtype in frappe.db.type_map
  32. and frappe.db.type_map.get(col.fieldtype)[0]
  33. not in ('text', 'longtext')):
  34. create_index_query += 'CREATE INDEX IF NOT EXISTS "{index_name}" ON `{table_name}`(`{field}`);'.format(
  35. index_name=col.fieldname,
  36. table_name=self.table_name,
  37. field=col.fieldname
  38. )
  39. if create_index_query:
  40. # nosemgrep
  41. frappe.db.sql(create_index_query)
  42. def alter(self):
  43. for col in self.columns.values():
  44. col.build_for_alter_table(self.current_columns.get(col.fieldname.lower()))
  45. query = []
  46. for col in self.add_column:
  47. query.append("ADD COLUMN `{}` {}".format(col.fieldname, col.get_definition()))
  48. for col in self.change_type:
  49. using_clause = ""
  50. if col.fieldtype in ("Datetime"):
  51. # The USING option of SET DATA TYPE can actually specify any expression
  52. # involving the old values of the row
  53. # read more https://www.postgresql.org/docs/9.1/sql-altertable.html
  54. using_clause = "USING {}::timestamp without time zone".format(col.fieldname)
  55. elif col.fieldtype in ("Check"):
  56. using_clause = "USING {}::smallint".format(col.fieldname)
  57. query.append("ALTER COLUMN `{0}` TYPE {1} {2}".format(
  58. col.fieldname,
  59. get_definition(col.fieldtype, precision=col.precision, length=col.length),
  60. using_clause
  61. ))
  62. for col in self.set_default:
  63. if col.fieldname=="name":
  64. continue
  65. if col.fieldtype in ("Check", "Int"):
  66. col_default = cint(col.default)
  67. elif col.fieldtype in ("Currency", "Float", "Percent"):
  68. col_default = flt(col.default)
  69. elif not col.default:
  70. col_default = "NULL"
  71. else:
  72. col_default = "{}".format(frappe.db.escape(col.default))
  73. query.append("ALTER COLUMN `{}` SET DEFAULT {}".format(col.fieldname, col_default))
  74. create_contraint_query = ""
  75. for col in self.add_index:
  76. # if index key not exists
  77. create_contraint_query += 'CREATE INDEX IF NOT EXISTS "{index_name}" ON `{table_name}`(`{field}`);'.format(
  78. index_name=col.fieldname,
  79. table_name=self.table_name,
  80. field=col.fieldname)
  81. for col in self.add_unique:
  82. # if index key not exists
  83. create_contraint_query += 'CREATE UNIQUE INDEX IF NOT EXISTS "unique_{index_name}" ON `{table_name}`(`{field}`);'.format(
  84. index_name=col.fieldname,
  85. table_name=self.table_name,
  86. field=col.fieldname
  87. )
  88. drop_contraint_query = ""
  89. for col in self.drop_index:
  90. # primary key
  91. if col.fieldname != 'name':
  92. # if index key exists
  93. drop_contraint_query += 'DROP INDEX IF EXISTS "{}" ;'.format(col.fieldname)
  94. for col in self.drop_unique:
  95. # primary key
  96. if col.fieldname != 'name':
  97. # if index key exists
  98. drop_contraint_query += 'DROP INDEX IF EXISTS "unique_{}" ;'.format(col.fieldname)
  99. try:
  100. if query:
  101. final_alter_query = "ALTER TABLE `{}` {}".format(self.table_name, ", ".join(query))
  102. # nosemgrep
  103. frappe.db.sql(final_alter_query)
  104. if create_contraint_query:
  105. # nosemgrep
  106. frappe.db.sql(create_contraint_query)
  107. if drop_contraint_query:
  108. # nosemgrep
  109. frappe.db.sql(drop_contraint_query)
  110. except Exception as e:
  111. # sanitize
  112. if frappe.db.is_duplicate_fieldname(e):
  113. frappe.throw(str(e))
  114. elif frappe.db.is_duplicate_entry(e):
  115. fieldname = str(e).split("'")[-2]
  116. frappe.throw(
  117. _("{0} field cannot be set as unique in {1}, as there are non-unique existing values")
  118. .format(fieldname, self.table_name)
  119. )
  120. else:
  121. raise e