mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fixed following schema diff issues:
1) Version mismatch should be displayed if you select EPAS 11 as the source and EPAS 12 as the target. 2) We should handle schema diff if the user stops the server after compare. 3) The data type is not visible for column headers in the query tool/view data. 4) Difference SQL is shown, though source & target SQL are same. 5) Error is shown when the 'target only' table is selected & clicked on Generate Script. 6) Difference SQL generated on deleting primary constraints from source throwing error on running from query tool. 7) Copy button for Difference SQL does not work. 8) Incorrect SQL is generated when check constraint from the source table is dropped. 9) Difference SQL is NOT shown when 'Unique Constraint' is dropped from the source table. 10) In case of difference, no message displayed related to copied successfully or not. 11) create or replace trigger should be on the next line. 12) Comparison Result of exactly identical tables having foreign key constraints is shown as different. 13) The wrong SQL displayed in the difference tab for view and materialized view for the select statements. 14) Wrong SQL displayed for the procedure in the difference section. 15) If the user already opens the compare section of Schema diff tool and Disconnects the server then '<' not supported between instances of 'NoneType' and 'int' message displayed. 16) When 'check constraint' is added on the source table which has already unique constraint & identical target table is created, all SQL panels remain empty. 17) Difference SQL is NOT shown when after adding 'Foreign Key' constraint to existing source table. 18) Incorrect SQL is generated when the existing index on the source table is modified. 19) Wrong SQL displayed for function in difference section. 20) Additional space is added before & after in difference SQL generated on the addition of an index to the source table. 21) Difference SQL is NOT shown when tables have different permission/grants. 22) Incorrect SQL is shown when the source had inherited table & target has a normal table. 23) Exactly identical child(inherited) tables show difference SQL. 24) Comparison is NOT working when the custom vacuum is enabled & one of the parameter modified & again custom vacuum is disabled.
This commit is contained in:
parent
f167d77b61
commit
c418a9c9ca
@ -38,7 +38,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -40,7 +40,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -35,7 +35,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -36,7 +36,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -38,7 +38,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -34,7 +34,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -40,7 +40,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -35,7 +35,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -36,7 +36,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -38,7 +38,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -34,7 +34,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -28,7 +28,7 @@ CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({% if
|
||||
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral }}{% endif %}{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -37,7 +37,7 @@ CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({% if
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
AS {% if 'probin' in data or 'prosrc_c' in data %}
|
||||
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
|
||||
{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %}
|
||||
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
|
||||
{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %}
|
||||
|
@ -837,5 +837,4 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, PackageView)
|
||||
PackageView.register_node_view(blueprint)
|
||||
|
@ -1607,10 +1607,21 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
data={'total_rows': count}
|
||||
)
|
||||
|
||||
def get_delete_sql(self, res):
|
||||
self.cmd = 'delete'
|
||||
sql = super(TableView, self).get_delete_sql(res)
|
||||
self.cmd = None
|
||||
@BaseTableView.check_precondition
|
||||
def get_drop_sql(self, sid, did, scid, tid):
|
||||
SQL = render_template("/".join(
|
||||
[self.table_template_path, 'properties.sql']),
|
||||
did=did, scid=scid, tid=tid,
|
||||
datlastsysoid=self.datlastsysoid
|
||||
)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
sql = ''
|
||||
|
||||
if status:
|
||||
self.cmd = 'delete'
|
||||
sql = super(TableView, self).get_delete_sql(res)
|
||||
self.cmd = None
|
||||
|
||||
return sql
|
||||
|
||||
@BaseTableView.check_precondition
|
||||
|
@ -101,6 +101,7 @@ def get_check_constraint_sql(conn, tid, data, template_path=None):
|
||||
if 'deleted' in constraint:
|
||||
for c in constraint['deleted']:
|
||||
c['schema'] = data['schema']
|
||||
c['nspname'] = data['schema']
|
||||
c['table'] = data['name']
|
||||
|
||||
# Sql for drop
|
||||
|
@ -137,14 +137,22 @@ def get_index_constraint_sql(conn, did, tid, data, template_path=None):
|
||||
# If constraint(s) is/are deleted
|
||||
if 'deleted' in constraint:
|
||||
for c in constraint['deleted']:
|
||||
c['schema'] = data['schema']
|
||||
c['table'] = data['name']
|
||||
del_cols = []
|
||||
if 'columns_to_be_dropped' in data:
|
||||
del_cols = list(map(lambda x, y: x['column'] in y,
|
||||
c['columns'],
|
||||
data['columns_to_be_dropped'])
|
||||
)
|
||||
|
||||
# Sql for drop
|
||||
sql.append(render_template("/".join([template_path,
|
||||
'delete.sql']),
|
||||
data=c,
|
||||
conn=conn).strip('\n'))
|
||||
if len(del_cols) == 0:
|
||||
c['schema'] = data['schema']
|
||||
c['table'] = data['name']
|
||||
|
||||
# Sql for drop
|
||||
sql.append(render_template("/".join([template_path,
|
||||
'delete.sql']),
|
||||
data=c,
|
||||
conn=conn).strip('\n'))
|
||||
if 'changed' in constraint:
|
||||
for c in constraint['changed']:
|
||||
c['schema'] = data['schema']
|
||||
|
@ -834,23 +834,35 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
schema = ''
|
||||
if data:
|
||||
schema = self.schema
|
||||
|
||||
data['schema'] = self.schema
|
||||
data['nspname'] = self.schema
|
||||
data['table'] = self.table
|
||||
|
||||
sql, name = index_utils.get_sql(
|
||||
self.conn, data, did, tid, idx, self.datlastsysoid,
|
||||
mode='create')
|
||||
|
||||
sql = sql.strip('\n').strip(' ')
|
||||
|
||||
elif diff_schema:
|
||||
schema = diff_schema
|
||||
|
||||
sql = index_utils.get_reverse_engineered_sql(
|
||||
self.conn, schema,
|
||||
self.table, did, tid, idx,
|
||||
self.datlastsysoid,
|
||||
template_path=None, with_header=False)
|
||||
sql = index_utils.get_reverse_engineered_sql(
|
||||
self.conn, schema,
|
||||
self.table, did, tid, idx,
|
||||
self.datlastsysoid,
|
||||
template_path=None, with_header=False)
|
||||
|
||||
drop_sql = ''
|
||||
if drop_req:
|
||||
drop_sql = '\n' + render_template(
|
||||
"/".join([self.template_path, 'delete.sql']),
|
||||
data=data, conn=self.conn
|
||||
)
|
||||
drop_sql = '\n' + self.delete(gid=1, sid=sid, did=did,
|
||||
scid=scid, tid=tid,
|
||||
idx=idx, only_sql=True)
|
||||
|
||||
return drop_sql + '\n\n' + sql
|
||||
if drop_sql != '':
|
||||
sql = drop_sql + '\n\n' + sql
|
||||
return sql
|
||||
|
||||
@check_precondition
|
||||
def dependents(self, gid, sid, did, scid, tid, idx):
|
||||
@ -1077,14 +1089,24 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
for key in required_create_keys:
|
||||
if key in diff_dict:
|
||||
create_req = True
|
||||
if key == 'columns' and ((
|
||||
'added' in diff_dict[key] and
|
||||
len(diff_dict[key]['added']) > 0
|
||||
) or ('changed' in diff_dict[key] and
|
||||
len(diff_dict[key]['changed']) > 0) or (
|
||||
'deleted' in diff_dict[key] and
|
||||
len(diff_dict[key]['deleted']) > 0)
|
||||
):
|
||||
create_req = True
|
||||
elif key != 'columns':
|
||||
create_req = True
|
||||
|
||||
if create_req:
|
||||
diff = self.get_sql_from_index_diff(sid=src_sid,
|
||||
did=src_did,
|
||||
scid=src_scid,
|
||||
tid=src_tid,
|
||||
idx=src_oid,
|
||||
diff = self.get_sql_from_index_diff(sid=tar_sid,
|
||||
did=tar_did,
|
||||
scid=tar_scid,
|
||||
tid=tar_tid,
|
||||
idx=tar_oid,
|
||||
diff_schema=target_schema,
|
||||
drop_req=True)
|
||||
else:
|
||||
|
@ -32,6 +32,7 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
'columns',
|
||||
'edit_types',
|
||||
'primary_key',
|
||||
'unique_constraint',
|
||||
'exclude_constraint',
|
||||
'check_constraint',
|
||||
'foreign_key',
|
||||
@ -188,15 +189,9 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
scid=tar_scid,
|
||||
tid=tar_oid,
|
||||
json_resp=False)
|
||||
SQL = render_template(
|
||||
"/".join([self.table_template_path, 'properties.sql']),
|
||||
did=tar_did, scid=tar_scid, tid=tar_oid,
|
||||
datlastsysoid=self.datlastsysoid
|
||||
)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
|
||||
if status:
|
||||
diff = self.get_delete_sql(res)
|
||||
diff = self.get_drop_sql(sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_oid)
|
||||
|
||||
elif comp_status == SchemaDiffModel.COMPARISON_STATUS['different']:
|
||||
source = self.fetch_tables(
|
||||
@ -230,10 +225,10 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
diff_dict.update(col_diff)
|
||||
|
||||
# Constraint comparison
|
||||
pk_diff = self.constraint_ddl_comp(source, target)
|
||||
pk_diff = self.constraint_ddl_comp(source, target, diff_dict)
|
||||
diff_dict.update(pk_diff)
|
||||
|
||||
diff_dict['relacl'] = self.parce_acl(source, target)
|
||||
diff_dict.update(self.parce_acl(source, target))
|
||||
|
||||
if not generate_script:
|
||||
source = self.get_sql_from_table_diff(sid=src_sid,
|
||||
@ -308,7 +303,7 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
|
||||
)
|
||||
if child_diff:
|
||||
diff += child_diff
|
||||
diff += '\n' + child_diff
|
||||
elif result:
|
||||
# For partition module
|
||||
identical = False
|
||||
@ -348,7 +343,7 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
comp_status=res['status']
|
||||
|
||||
)
|
||||
if ddl_compare:
|
||||
if child_diff:
|
||||
diff += child_diff
|
||||
else:
|
||||
diff = self.get_sql_from_table_diff(
|
||||
@ -418,7 +413,7 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
return different
|
||||
|
||||
@staticmethod
|
||||
def constraint_ddl_comp(source_table, target_table):
|
||||
def constraint_ddl_comp(source_table, target_table, diff_dict):
|
||||
"""
|
||||
Table Constraint DDL comparison
|
||||
:param source: Source Table
|
||||
@ -427,19 +422,26 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
"""
|
||||
different = {}
|
||||
non_editable_keys = {}
|
||||
columns_to_be_dropped = []
|
||||
|
||||
non_editable_keys = {'primary_key': ['col_count',
|
||||
'condeferrable',
|
||||
'condeffered',
|
||||
'columns'],
|
||||
'unique_constraint': ['col_count',
|
||||
'condeferrable',
|
||||
'condeffered',
|
||||
'columns'],
|
||||
'check_constraint': ['consrc'],
|
||||
'exclude_constraint': ['amname',
|
||||
'indconstraint',
|
||||
'columns']
|
||||
'columns'],
|
||||
'foreign_key': []
|
||||
}
|
||||
|
||||
for constraint in ['primary_key', 'check_constraint',
|
||||
'exclude_constraint']:
|
||||
for constraint in ['primary_key', 'unique_constraint',
|
||||
'check_constraint',
|
||||
'exclude_constraint', 'foreign_key']:
|
||||
source_cols = source_table[constraint] if \
|
||||
constraint in source_table else []
|
||||
target_cols = copy.deepcopy(target_table[constraint]) if\
|
||||
@ -472,7 +474,7 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
tmp_updated = None
|
||||
break
|
||||
if tmp_updated:
|
||||
tmp_updated['oid'] = tmp_tar['oid']
|
||||
tmp_updated['oid'] = tmp['oid']
|
||||
updated.append(tmp_updated)
|
||||
target_cols.remove(tmp)
|
||||
elif tmp_tar and tmp_src == tmp_tar:
|
||||
|
@ -91,7 +91,7 @@ PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
|
||||
EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
|
||||
|
||||
{% endif %}
|
||||
{% if data.description is defined %}
|
||||
{% if data.description is defined and data.description != None %}
|
||||
{% if data.name %}
|
||||
COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
|
||||
{% else %}
|
||||
|
@ -9,7 +9,7 @@ ALTER INDEX {{conn|qtIdent(data.schema, o_data.name)}}
|
||||
ALTER INDEX {{conn|qtIdent(data.schema, data.name)}}
|
||||
SET (FILLFACTOR={{data.fillfactor}});
|
||||
|
||||
{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %}
|
||||
{% elif (data.fillfactor == '' or data.fillfactor == None) and o_data.fillfactor|default('', 'true') != data.fillfactor %}
|
||||
ALTER INDEX {{conn|qtIdent(data.schema, data.name)}}
|
||||
RESET (FILLFACTOR);
|
||||
|
||||
|
@ -883,7 +883,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
old_col_data['cltype'])
|
||||
|
||||
# Sql for alter column
|
||||
if 'inheritedfrom' not in c:
|
||||
if 'inheritedfrom' not in c and\
|
||||
'inheritedfromtable' not in c:
|
||||
column_sql += render_template("/".join(
|
||||
[self.column_template_path, 'update.sql']),
|
||||
data=c, o_data=old_col_data, conn=self.conn
|
||||
@ -897,7 +898,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
|
||||
c = column_utils.convert_length_precision_to_string(c)
|
||||
|
||||
if 'inheritedfrom' not in c:
|
||||
if 'inheritedfrom' not in c and\
|
||||
'inheritedfromtable' not in c:
|
||||
column_sql += render_template("/".join(
|
||||
[self.column_template_path, 'create.sql']),
|
||||
data=c, conn=self.conn).strip('\n') + '\n\n'
|
||||
@ -950,6 +952,11 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
# Combine all the SQL together
|
||||
SQL += '\n' + partitions_sql.strip('\n')
|
||||
|
||||
data['columns_to_be_dropped'] = []
|
||||
if 'columns' in data and 'deleted' in data['columns']:
|
||||
data['columns_to_be_dropped'] = list(map(
|
||||
lambda d: d['name'], data['columns']['deleted']))
|
||||
|
||||
# Check if index constraints are added/changed/deleted
|
||||
index_constraint_sql = \
|
||||
idxcons_utils.get_index_constraint_sql(
|
||||
@ -1501,11 +1508,12 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
for data_row in data[vacuum_key]['changed']:
|
||||
for old_data_row in old_data[vacuum_key]:
|
||||
if data_row['name'] == old_data_row['name']:
|
||||
if data_row['value'] is not None:
|
||||
set_values.append(data_row)
|
||||
elif data_row['value'] is None and \
|
||||
'value' in old_data_row:
|
||||
reset_values.append(data_row)
|
||||
if 'value' in data_row:
|
||||
if data_row['value'] is not None:
|
||||
set_values.append(data_row)
|
||||
elif data_row['value'] is None and \
|
||||
'value' in old_data_row:
|
||||
reset_values.append(data_row)
|
||||
|
||||
if len(set_values) > 0:
|
||||
data[vacuum_key]['set_values'] = set_values
|
||||
|
@ -399,8 +399,11 @@ def compare(trans_id, source_sid, source_did, source_scid,
|
||||
if error_msg == gettext('Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg, status=404)
|
||||
|
||||
if not check_version_compatibility(source_sid, target_sid):
|
||||
return not_implemented(errormsg=gettext("Version mismatch."))
|
||||
# Server version compatibility check
|
||||
status, msg = check_version_compatibility(source_sid, target_sid)
|
||||
|
||||
if not status:
|
||||
return make_json_response(success=0, errormsg=msg, status=404)
|
||||
|
||||
comparison_result = []
|
||||
|
||||
@ -584,18 +587,24 @@ def check_version_compatibility(sid, tid):
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
src_server = Server.query.filter_by(id=sid).first()
|
||||
src_manager = driver.connection_manager(src_server.id)
|
||||
src_conn = src_manager.connection()
|
||||
|
||||
tar_server = Server.query.filter_by(id=tid).first()
|
||||
tar_manager = driver.connection_manager(tar_server.id)
|
||||
tar_conn = tar_manager.connection()
|
||||
|
||||
if not (src_conn.connected() or src_conn.connected()):
|
||||
return False, gettext('Server(s) disconnected.')
|
||||
|
||||
def get_round_val(x):
|
||||
if x < 10000:
|
||||
return x if x % 100 == 0 else x + 100 - x % 100
|
||||
else:
|
||||
return x if x % 10000 == 0 else x + 10000 - x % 10000
|
||||
return x + 10000 - x % 10000
|
||||
|
||||
if get_round_val(src_manager.version) == \
|
||||
get_round_val(tar_manager.version):
|
||||
return True
|
||||
return True, None
|
||||
|
||||
return False
|
||||
return False, gettext('Source and Target database server must be of '
|
||||
'the same major version.')
|
||||
|
@ -220,46 +220,54 @@ def directory_diff(source_dict, target_dict, ignore_keys=[], difference={}):
|
||||
ignore_keys, difference)
|
||||
elif type(source_dict[key]) is list:
|
||||
tmp_target = None
|
||||
for index in range(len(source_dict[key])):
|
||||
source = copy.deepcopy(source_dict[key][index])
|
||||
if type(source) is list:
|
||||
# TODO
|
||||
pass
|
||||
elif type(source) is dict:
|
||||
if 'name' in source or 'colname' in source:
|
||||
if type(target_dict[key]) is list and len(
|
||||
target_dict[key]) > 0:
|
||||
tmp = None
|
||||
tmp_target = copy.deepcopy(target_dict[key])
|
||||
for item in tmp_target:
|
||||
if (
|
||||
'name' in item and
|
||||
item['name'] == source['name']
|
||||
) or (
|
||||
'colname' in item and
|
||||
item['colname'] == source['colname']
|
||||
):
|
||||
tmp = copy.deepcopy(item)
|
||||
if tmp and source != tmp:
|
||||
updated.append(copy.deepcopy(source))
|
||||
tmp_target.remove(tmp)
|
||||
elif tmp and source == tmp:
|
||||
tmp_target.remove(tmp)
|
||||
elif tmp is None:
|
||||
tmp_list = list(filter(
|
||||
lambda x: type(x) == list or type(x) == dict, source_dict[key]
|
||||
))
|
||||
|
||||
if len(tmp_list) > 0:
|
||||
for index in range(len(source_dict[key])):
|
||||
source = copy.deepcopy(source_dict[key][index])
|
||||
if type(source) is list:
|
||||
# TODO
|
||||
pass
|
||||
elif type(source) is dict:
|
||||
if 'name' in source or 'colname' in source:
|
||||
if type(target_dict[key]) is list and len(
|
||||
target_dict[key]) > 0:
|
||||
tmp = None
|
||||
tmp_target = copy.deepcopy(target_dict[key])
|
||||
for item in tmp_target:
|
||||
if (
|
||||
'name' in item and
|
||||
item['name'] == source['name']
|
||||
) or (
|
||||
'colname' in item and
|
||||
item['colname'] == source[
|
||||
'colname']
|
||||
):
|
||||
tmp = copy.deepcopy(item)
|
||||
if tmp and source != tmp:
|
||||
updated.append(copy.deepcopy(source))
|
||||
tmp_target.remove(tmp)
|
||||
elif tmp and source == tmp:
|
||||
tmp_target.remove(tmp)
|
||||
elif tmp is None:
|
||||
added.append(source)
|
||||
else:
|
||||
added.append(source)
|
||||
else:
|
||||
added.append(source)
|
||||
difference[key] = {}
|
||||
difference[key]['added'] = added
|
||||
difference[key]['changed'] = updated
|
||||
elif target_dict[key] is None or \
|
||||
(type(target_dict[key]) is list and
|
||||
len(target_dict[key]) < index and
|
||||
source != target_dict[key][index]):
|
||||
difference[key] = source
|
||||
elif type(target_dict[key]) is list and\
|
||||
len(target_dict[key]) > index:
|
||||
difference[key] = source
|
||||
difference[key] = {}
|
||||
difference[key]['added'] = added
|
||||
difference[key]['changed'] = updated
|
||||
elif target_dict[key] is None or \
|
||||
(type(target_dict[key]) is list and
|
||||
len(target_dict[key]) < index and
|
||||
source != target_dict[key][index]):
|
||||
difference[key] = source
|
||||
elif type(target_dict[key]) is list and\
|
||||
len(target_dict[key]) > index:
|
||||
difference[key] = source
|
||||
else:
|
||||
target_dict[key] = source_dict[key]
|
||||
|
||||
if type(source) is dict and tmp_target and key in tmp_target and \
|
||||
tmp_target[key] and len(tmp_target[key]) > 0:
|
||||
|
@ -50,7 +50,7 @@
|
||||
padding: 5px 5px !important;
|
||||
}
|
||||
|
||||
.slick-header-column.ui-state-default {
|
||||
#schema-diff-grid .slick-header-column.ui-state-default {
|
||||
height: 32px !important;
|
||||
line-height: 25px !important;
|
||||
}
|
||||
|
@ -69,6 +69,13 @@ let SchemaDiffSqlControl =
|
||||
copyData() {
|
||||
event.stopPropagation();
|
||||
clipboard.copyTextToClipboard(this.model.get('diff_ddl'));
|
||||
this.$el.find('.ddl-copy').text(gettext('Copied!'));
|
||||
var self = this;
|
||||
setTimeout(function() {
|
||||
let $copy = self.$el.find('.ddl-copy');
|
||||
if (!$copy.hasClass('d-none')) $copy.addClass('d-none');
|
||||
$copy.text(gettext('Copy'));
|
||||
}, 3000);
|
||||
return false;
|
||||
},
|
||||
onFocus: function() {
|
||||
@ -78,14 +85,6 @@ let SchemaDiffSqlControl =
|
||||
if ($copy.hasClass('d-none')) $copy.removeClass('d-none');
|
||||
|
||||
},
|
||||
onBlur: function() {
|
||||
let $copy = this.$el.find('.ddl-copy');
|
||||
if (!$(event.relatedTarget).hasClass('ddl-copy')) {
|
||||
if (!$copy.hasClass('d-none')) $copy.addClass('d-none');
|
||||
this.$el.find('.pgadmin-controls').first().removeClass('focused');
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
let SchemaDiffSelect2Control =
|
||||
@ -302,7 +301,8 @@ let SchemaDiffHeaderView = Backform.Form.extend({
|
||||
<button id="btn-filter" type="button" class="btn btn-sm btn-secondary"
|
||||
title=""
|
||||
accesskey=""
|
||||
tabindex="0">
|
||||
tabindex="0"
|
||||
style="pointer-events: none;">
|
||||
<i class="fa fa-filter sql-icon-lg" aria-hidden="true"></i> ` + gettext('Filter') + `
|
||||
</button>
|
||||
<button id="btn-filter-dropdown" type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split"
|
||||
@ -315,7 +315,7 @@ let SchemaDiffHeaderView = Backform.Form.extend({
|
||||
'<ul class="dropdown-menu filter">',
|
||||
'<li>',
|
||||
'<a class="dropdown-item" id="btn-identical" href="#" tabindex="0">',
|
||||
'<i class="identical fa fa-check" aria-hidden="true"></i>',
|
||||
'<i class="identical fa fa-check visibility-hidden" aria-hidden="true"></i>',
|
||||
'<span> ' + gettext('Identical') + ' </span>',
|
||||
'</a>',
|
||||
'</li>',
|
||||
|
@ -37,7 +37,7 @@ define('pgadmin.schemadiff', [
|
||||
applies: ['tools'],
|
||||
callback: 'show_schema_diff_tool',
|
||||
priority: 1,
|
||||
label: gettext('Schema Diff'),
|
||||
label: gettext('Schema Diff (Beta)'),
|
||||
enable: true,
|
||||
}];
|
||||
|
||||
@ -85,7 +85,7 @@ define('pgadmin.schemadiff', [
|
||||
})
|
||||
.done(function(res) {
|
||||
self.trans_id = res.data.schemaDiffTransId;
|
||||
res.data.panel_title = 'Schema Diff'; //TODO: Set the panel title
|
||||
res.data.panel_title = 'Schema Diff (Beta)'; //TODO: Set the panel title
|
||||
// TODO: Following function is used to test the fetching of the
|
||||
// databases this should be moved to server selection event later.
|
||||
self.launch_schema_diff(res.data);
|
||||
|
@ -31,7 +31,7 @@ export default class SchemaDiffUI {
|
||||
this.header = null;
|
||||
this.trans_id = trans_id;
|
||||
this.filters = ['Identical', 'Different', 'Source Only', 'Target Only'];
|
||||
this.sel_filters = ['Identical', 'Different', 'Source Only', 'Target Only'];
|
||||
this.sel_filters = ['Different', 'Source Only', 'Target Only'];
|
||||
this.dataView = null;
|
||||
this.grid = null,
|
||||
this.selection = {};
|
||||
@ -229,8 +229,12 @@ export default class SchemaDiffUI {
|
||||
server_data['did'] = self.model.get('target_did');
|
||||
server_data['database'] = data.database;
|
||||
|
||||
if (_.isUndefined(generated_script))
|
||||
generated_script = 'BEGIN;' + '\n' + self.model.get('diff_ddl') + '\n' + 'END;';
|
||||
if (_.isUndefined(generated_script)) {
|
||||
generated_script = gettext('-- The generated script does not include the dependency resolution currently, so it may fail in case of dependency. \n');
|
||||
generated_script += gettext('-- Please report an issue at https://redmine.postgresql.org/projects/pgadmin4/issues/new \n');
|
||||
|
||||
generated_script += 'BEGIN;' + '\n' + self.model.get('diff_ddl') + '\n' + 'END;';
|
||||
}
|
||||
|
||||
let preferences = pgWindow.pgAdmin.Browser.get_preferences_for_module('schema_diff');
|
||||
if (preferences.schema_diff_new_browser_tab) {
|
||||
|
Loading…
Reference in New Issue
Block a user