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:
Khushboo Vashi
2020-01-28 14:53:17 +05:30
committed by Akshay Joshi
parent f167d77b61
commit c418a9c9ca
28 changed files with 199 additions and 127 deletions

View File

@@ -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.')

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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>&nbsp;` + 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>',

View File

@@ -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);

View File

@@ -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) {