Fixed following issue of schema diff tool:

1. Comparison result of 2 exact identical Trigger Functions is different
 2. EPAS 12: Table comparison with the compound trigger shown as different, but all SQL panels are blank
 3. Compound trigger properties panel is not opening
 4. The DDL difference of the table containing the foreign key is not accurate
 5. The DDL difference of the view which refers the table from schema is not accurate
 6. DDL comparison fails if we have procedure with plpgsql in source and edbsql in target
This commit is contained in:
Khushboo Vashi 2020-01-31 21:28:08 +05:30 committed by Akshay Joshi
parent 210bbfdbe1
commit 3b1c8abd2f
13 changed files with 54 additions and 33 deletions

View File

@ -1146,13 +1146,13 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
data['pronamespace'] = self._get_schema(
data['pronamespace']
)
if 'provolatile' in data:
if 'provolatile' in data and data['provolatile']:
data['provolatile'] = vol_dict[data['provolatile']]
if fnid is not None:
# Edit Mode
if 'proparallel' in data:
if 'proparallel' in data and data['proparallel']:
data['proparallel'] = parallel_dict[data['proparallel']]
# Fetch Old Data from database.

View File

@ -31,7 +31,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -30,7 +30,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -31,7 +31,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -29,7 +29,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -30,7 +30,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -31,7 +31,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -29,7 +29,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}()
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 %}

View File

@ -13,7 +13,7 @@ import simplejson as json
from functools import wraps
import pgadmin.browser.server_groups.servers.databases as database
from flask import render_template, request, jsonify
from flask import render_template, request, jsonify, current_app
from flask_babelex import gettext
from pgadmin.browser.collection import CollectionNodeModule
from pgadmin.browser.utils import PGChildNodeView
@ -30,6 +30,7 @@ from pgadmin.utils.compile_template_name import compile_template_path
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
# If we are in Python3
if not IS_PY2:
unicode = str
@ -431,10 +432,14 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
JSON of selected compound trigger node
"""
data = self._fetch_properties(tid, trid)
status, data = self._fetch_properties(tid, trid)
if not status:
return data
return internal_server_error(errormsg=data)
if 'rows' in data and len(data['rows']) == 0:
return gone(gettext(
"""Could not find the compound trigger in the table."""))
return ajax_response(
response=data,
@ -451,11 +456,10 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
return status, res
if len(res['rows']) == 0:
return gone(gettext(
"""Could not find the compound trigger in the table."""))
return True, res
# Making copy of output for future use
data = dict(res['rows'][0])
@ -876,7 +880,10 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
def get_sql_from_diff(self, gid, sid, did, scid, tid, oid,
data=None, diff_schema=None, drop_sql=False):
if data:
sql, name = self.get_sql(scid, tid, oid, data)
sql, name = compound_trigger_utils.get_sql(self.conn,
data,
tid, oid,
self.datlastsysoid)
if not isinstance(sql, (str, unicode)):
return sql
sql = sql.strip('\n').strip(' ')
@ -908,21 +915,16 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
columns = ', '.join(data['tgattr'].split(' '))
data['columns'] = self._column_details(tid, columns)
data = self._trigger_definition(data)
data = trigger_definition(data)
if diff_schema:
data['schema'] = diff_schema
SQL, name = self.get_sql(scid, tid, None, data)
sql_header = u"-- Compound Trigger: {0}\n\n-- ".format(
data['name'])
sql_header += render_template("/".join([self.template_path,
'delete.sql']),
data=data, conn=self.conn)
SQL = sql_header + '\n\n' + SQL.strip('\n')
SQL, name = compound_trigger_utils.get_sql(self.conn,
data,
tid,
None,
self.datlastsysoid)
# If compound trigger is disbaled then add sql
# code for the same

View File

@ -275,8 +275,21 @@ def get_sql(conn, data, tid, fkid=None, template_path=None):
# Get the parent schema and table.
schema, table = get_parent(conn,
data['columns'][0]['references'])
data['remote_schema'] = schema
data['remote_table'] = table
# Below handling will be used in Schema diff in case
# of different database comparison
if schema and table:
data['remote_schema'] = schema
data['remote_table'] = table
if 'remote_schema' not in data:
data['remote_schema'] = None
elif 'schema' in data and (schema is None or schema == ''):
data['remote_schema'] = data['schema']
if 'remote_table' not in data:
data['remote_table'] = None
sql = render_template("/".join([template_path, 'create.sql']),
data=data, conn=conn)

View File

@ -249,8 +249,7 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
})
# Schema Diff: Keys to ignore while comparing
keys_to_ignore = ['oid', 'xmin', 'nspname', 'tfunction',
'tgrelid', 'tgfoid', 'prosrc']
keys_to_ignore = ['oid', 'xmin', 'nspname', 'tgrelid', 'tgfoid', 'prosrc']
def check_precondition(f):
"""

View File

@ -1145,6 +1145,9 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
result = res['rows'][0]
if diff_schema:
result['definition'] = result['definition'].replace(
result['schema'],
diff_schema)
result['schema'] = diff_schema
# sending result to formtter
@ -1753,6 +1756,9 @@ class MViewNode(ViewNode, VacuumSettings):
result = res['rows'][0]
if diff_schema:
result['definition'] = result['definition'].replace(
result['schema'],
diff_schema)
result['schema'] = diff_schema
# sending result to formtter

View File

@ -230,8 +230,9 @@ export default class SchemaDiffUI {
server_data['database'] = data.database;
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 = gettext('-- This script is generated by \'Schema Diff\' utility of pgAdmin 4. \n');
generated_script += gettext('-- It does not include the dependency resolution logic, hence - it may not be able to resolve some dependent database object differences. \n');
generated_script += gettext('-- Please report an issue for any failure with the reproduction steps. \n');
generated_script += 'BEGIN;' + '\n' + self.model.get('diff_ddl') + '\n' + 'END;';
}