Modified schema diff tool to compare two databases instead of two schemas. Fixes #5126

This commit is contained in:
Akshay Joshi
2020-08-10 15:13:34 +05:30
parent 3672013ddc
commit 4f74609ecf
72 changed files with 1622 additions and 741 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 228 KiB

View File

@@ -10,6 +10,7 @@ New features
************ ************
| `Issue #3904 <https://redmine.postgresql.org/issues/3904>`_ - Replace charting library Flotr2 with ChartJS using React. | `Issue #3904 <https://redmine.postgresql.org/issues/3904>`_ - Replace charting library Flotr2 with ChartJS using React.
| `Issue #5126 <https://redmine.postgresql.org/issues/5126>`_ - Modified schema diff tool to compare two databases instead of two schemas.
| `Issue #5610 <https://redmine.postgresql.org/issues/5610>`_ - Add a --yes command line option to setup-web.sh to allow non-interactive use. | `Issue #5610 <https://redmine.postgresql.org/issues/5610>`_ - Add a --yes command line option to setup-web.sh to allow non-interactive use.
Housekeeping Housekeeping

View File

@@ -4,29 +4,29 @@
`Schema Diff`:index: `Schema Diff`:index:
******************** ********************
**Schema Diff** is a feature that allows you to compare schema objects between **Schema Diff** is a feature that allows you to compare objects between
two database schemas. Use the *Tools* menu to access Schema Diff. two databases. Use the *Tools* menu to access Schema Diff.
The Schema Diff feature allows you to: The Schema Diff feature allows you to:
* Compare and synchronize the database schemas (from source to target). * Compare and synchronize the database objects (from source to target).
* Visualize the differences between database schemas. * Visualize the differences between database objects.
* List the differences in SQL statement for target schema objects. * List the differences in SQL statement for target database objects.
* Generate synchronization scripts. * Generate synchronization scripts.
**Note** - The source and target databases must be of the same major **Note** - The source and target database servers must be of the same major
version. version.
Click on *Schema Diff* under the *Tools* menu to open a selection panel. Choose Click on *Schema Diff* under the *Tools* menu to open a selection panel. Choose
the source and target servers, databases, and schemas that will be the source and target servers, and databases that will be
compared. After selecting the objects, click on the *Compare* button. compared. After selecting the objects, click on the *Compare* button.
You can open multiple copies of *Schema Diff* in individual tabs You can open multiple copies of *Schema Diff* in individual tabs
simultaneously. To close a copy of Schema Diff, click the *X* in the simultaneously. To close a copy of Schema Diff, click the *X* in the
upper-right hand corner of the tab bar. upper-right hand corner of the tab bar.
.. image:: images/schema_diff_dialog.png .. image:: images/schema_diff_dialog.png
@@ -44,7 +44,7 @@ The Schema Diff Object Comparison Panel
======================================== ========================================
In the object comparison panel, you can select the source and target servers In the object comparison panel, you can select the source and target servers
of the same major version, databases, and schemas to be compared. You can of the same major version, and databases to be compared. You can
select any server listed under the browser tree whether it is connected or select any server listed under the browser tree whether it is connected or
disconnected. If you select a server that is not connected then it will disconnected. If you select a server that is not connected then it will
prompt you for the password before using the server. prompt you for the password before using the server.
@@ -52,40 +52,36 @@ prompt you for the password before using the server.
Next, select the databases that will be compared. The databases can be the Next, select the databases that will be compared. The databases can be the
same or different (and within the same server or from different servers). same or different (and within the same server or from different servers).
Lastly, select the source and target schemas which will be compared.
.. image:: images/schema_diff_compare_button.png .. image:: images/schema_diff_compare_button.png
:alt: Schema diff compare button :alt: Schema diff compare button
:align: center :align: center
After you select servers, databases, and schemas, click on the After you select servers, and databases, click on the
*Compare* button to obtain the *Comparison Result*. *Compare* button to obtain the *Comparison Result*.
.. image:: images/schema_diff_comparison_results.png .. image:: images/schema_diff_comparison_results.png
:alt: Schema diff comparison results :alt: Schema diff comparison results
:align: center :align: center
Use the drop-down lists of Functions, Materialized Views, Tables, Use the drop-down lists of Database Objects to view the DDL statements.
Trigger Functions, Procedures, and Views to view the DDL statements of
all the schema objects.
In the upper-right hand corner of the object comparison panel is a *Filter* In the upper-right hand corner of the object comparison panel is a *Filter*
option that you can use to filter the schema objects based on the option that you can use to filter the database objects based on the
following comparison criteria: following comparison criteria:
* Identical If the object is found in both schemas with the same SQL statement, then the comparison result is identical. * Identical If the object is found in both databases with the same SQL statement, then the comparison result is identical.
* Different If the object is found in both schemas but have different SQL statements, then the comparison result is different. * Different If the object is found in both databases but have different SQL statements, then the comparison result is different.
* Source Only If the object is found in source schema only and not in target schema, then the comparison result is source only. * Source Only If the object is found in source database only and not in target database, then the comparison result is source only.
* Target Only If the object is found in target schema only and not in source schema, then the comparison result is target only. * Target Only If the object is found in target database only and not in source database, then the comparison result is target only.
.. image:: images/schema_diff_filter_option.png .. image:: images/schema_diff_filter_option.png
:alt: Schema diff filter option :alt: Schema diff filter option
:align: center :align: center
Click on any of the schema objects in the object comparison panel to Click on any of the database objects in the object comparison panel to
display the DDL Statements of that object in the DDL Comparison panel. display the DDL Statements of that object in the DDL Comparison panel.
@@ -94,36 +90,32 @@ Schema Diff DDL Comparison Panel
The *DDL Comparison* panel displays three columns: The *DDL Comparison* panel displays three columns:
* The first column displays the DDL statement of the object from the source schema. * The first column displays the DDL statement of the object from the source database.
* The second column displays the DDL statement of the object from the target schema. * The second column displays the DDL statement of the object from the target database.
* The third column displays the difference in the SQL statement of the target schema object. * The third column displays the difference in the SQL statement of the target database object.
.. image:: images/schema_diff_DDL_comparison.png .. image:: images/schema_diff_DDL_comparison.png
:alt: Schema diff DDL comparison :alt: Schema diff DDL comparison
:align: center :align: center
You can review the DDL statements of all the schema objects to You can review the DDL statements of all the database objects to
check for the differences in the SQL statements. check for the differences in the SQL statements.
Also, you can generate the SQL script of the differences found in the Also, you can generate the SQL script of the differences found in the
target schema object based on the SQL statement of the source schema target database object based on the SQL statement of the source database
object. To generate the script, select the checkboxes of the schema object. To generate the script, select the checkboxes of the database
objects in the object comparison panel and then click on the *Generate Script* objects in the object comparison panel and then click on the *Generate Script*
button in the upper-right hand corner of the object comparison panel. button in the upper-right hand corner of the object comparison panel.
.. image:: images/schema_diff_generate_script.png Select the database objects and click on the *Generate Script*
:alt: Schema diff generate script
:align: center
Select the schema objects and click on the *Generate Script*
button to open the *Query Tool* in a new tab, with the difference button to open the *Query Tool* in a new tab, with the difference
in the SQL statement displayed in the *Query Editor*. in the SQL statement displayed in the *Query Editor*.
If you have clicked on the schema object to check the difference If you have clicked on the database object to check the difference
generated in the *DDL Comparison* Panel, and you have not selected the generated in the *DDL Comparison* Panel, and you have not selected the
checkbox of the schema object, PEM will open the *Query Tool* in a new checkbox of the database object, pgAdmin will open the *Query Tool* in a new
tab, with the differences in the SQL statements displayed in the *Query Editor*. tab, with the differences in the SQL statements displayed in the *Query Editor*.
You can also use the *Copy* button to copy the difference generated in You can also use the *Copy* button to copy the difference generated in
@@ -133,4 +125,4 @@ the *DDL Comparison* panel.
:alt: Schema diff generate script query editor :alt: Schema diff generate script query editor
:align: center :align: center
Apply the SQL Statement in the target schema to synchronize the schemas. Apply the SQL Statement in the target database to synchronize the databases.

View File

@@ -21,6 +21,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class CastModule(CollectionNodeModule): class CastModule(CollectionNodeModule):
@@ -88,7 +90,7 @@ class CastModule(CollectionNodeModule):
blueprint = CastModule(__name__) blueprint = CastModule(__name__)
class CastView(PGChildNodeView): class CastView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
class CastView(PGChildNodeView) class CastView(PGChildNodeView)
@@ -179,9 +181,12 @@ class CastView(PGChildNodeView):
'get_functions': [ 'get_functions': [
{'post': 'get_functions'}, {'post': 'get_functions'},
{'post': 'get_functions'} {'post': 'get_functions'}
] ],
'compare': [{'get': 'compare'}, {'get': 'compare'}]
}) })
keys_to_ignore = ['oid', 'id', 'oid-2']
def _init_(self, **kwargs): def _init_(self, **kwargs):
self.conn = None self.conn = None
self.template_path = None self.template_path = None
@@ -318,26 +323,41 @@ class CastView(PGChildNodeView):
:param cid: cast id :param cid: cast id
:return: :return:
""" """
status, res = self._fetch_properties(did, cid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, did, cid):
"""
This function fetch the properties of the
:param did:
:param cid:
:return:
"""
last_system_oid = 0 if self.blueprint.show_system_objects else \
self.datlastsysoid
sql = render_template( sql = render_template(
"/".join([self.template_path, self._PROPERTIES_SQL]), "/".join([self.template_path, self._PROPERTIES_SQL]),
cid=cid, cid=cid,
datlastsysoid=self.datlastsysoid, datlastsysoid=last_system_oid,
showsysobj=self.blueprint.show_system_objects showsysobj=self.blueprint.show_system_objects
) )
status, res = self.conn.execute_dict(sql) status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the cast information.") gettext("Could not find the cast information.")
) )
return ajax_response( return True, res['rows'][0]
response=res['rows'][0],
status=200
)
@check_precondition @check_precondition
def create(self, gid, sid, did): def create(self, gid, sid, did):
@@ -436,29 +456,42 @@ class CastView(PGChildNodeView):
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@staticmethod
def get_delete_data(cmd, cid, request_object):
"""
This function is used to get the data and cascade information.
:param cmd: Command
:param cid: Object ID
:param request_object: request object
:return:
"""
cascade = False
# Below will decide if it's simple drop or drop with cascade call
if cmd == 'delete':
# This is a cascade operation
cascade = True
if cid is None:
data = request_object.form if request_object.form else \
json.loads(request_object.data, encoding='utf-8')
else:
data = {'ids': [cid]}
return cascade, data
@check_precondition @check_precondition
def delete(self, gid, sid, did, cid=None): def delete(self, gid, sid, did, cid=None, only_sql=False):
""" """
This function will drop the cast object This function will drop the cast object
:param cid: cast id :param cid: cast id
:param did: database id :param did: database id
:param sid: server id :param sid: server id
:param gid: group id :param gid: group id
:param only_sql:
:return: :return:
""" """
# Below will decide if it's simple drop or drop with cascade call # get the value of cascade and data
if self.cmd == 'delete': cascade, data = self.get_delete_data(self.cmd, cid, request)
# This is a cascade operation
cascade = True
else:
cascade = False
if cid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [cid]}
for cid in data['ids']: for cid in data['ids']:
try: try:
@@ -490,6 +523,11 @@ class CastView(PGChildNodeView):
casttarget=result['casttarget'], casttarget=result['casttarget'],
cascade=cascade cascade=cascade
) )
# Used for schema diff tool
if only_sql:
return sql
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -638,13 +676,14 @@ class CastView(PGChildNodeView):
) )
@check_precondition @check_precondition
def sql(self, gid, sid, did, cid): def sql(self, gid, sid, did, cid, json_resp=True):
""" """
This function will generate sql for sql panel This function will generate sql for sql panel
:param gid: group id :param gid: group id
:param sid: server id :param sid: server id
:param did: database id :param did: database id
:param cid: cast id :param cid: cast id
:param json_resp:
:return: :return:
""" """
try: try:
@@ -653,6 +692,7 @@ class CastView(PGChildNodeView):
cid=cid, cid=cid,
conn=self.conn conn=self.conn
) )
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(gettext( return internal_server_error(gettext(
@@ -665,6 +705,9 @@ class CastView(PGChildNodeView):
"cast node." "cast node."
)) ))
if not json_resp:
return res
return ajax_response(response=res) return ajax_response(response=res)
except Exception as e: except Exception as e:
@@ -706,5 +749,63 @@ class CastView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the casts for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
last_system_oid = 0
if self.manager.db_info is not None and did in self.manager.db_info:
last_system_oid = (self.manager.db_info[did])['datlastsysoid']
sql = render_template(
"/".join([self.template_path, 'nodes.sql']),
datlastsysoid=last_system_oid,
showsysobj=self.blueprint.show_system_objects
)
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(did, row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs:
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql, name = self.get_sql(gid=gid, sid=sid, did=did, data=data,
cid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did,
cid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, cid=oid,
json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, CastView, 'Database')
CastView.register_node_view(blueprint) CastView.register_node_view(blueprint)

View File

@@ -20,6 +20,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class EventTriggerModule(CollectionNodeModule): class EventTriggerModule(CollectionNodeModule):
@@ -94,7 +96,7 @@ class EventTriggerModule(CollectionNodeModule):
blueprint = EventTriggerModule(__name__) blueprint = EventTriggerModule(__name__)
class EventTriggerView(PGChildNodeView): class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
class EventTriggerView(PGChildNodeView) class EventTriggerView(PGChildNodeView)
@@ -172,6 +174,8 @@ class EventTriggerView(PGChildNodeView):
'fopts': [{'get': 'get_event_funcs'}, {'get': 'get_event_funcs'}] 'fopts': [{'get': 'get_event_funcs'}, {'get': 'get_event_funcs'}]
}) })
keys_to_ignore = ['oid', 'xmin', 'oid-2', 'eventfuncoid']
def check_precondition(f): def check_precondition(f):
""" """
This function will behave as a decorator which will checks This function will behave as a decorator which will checks
@@ -325,6 +329,22 @@ class EventTriggerView(PGChildNodeView):
Returns: Returns:
"""
status, res = self._fetch_properties(did, etid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, did, etid):
"""
This function fetch the properties of the event trigger.
:param did:
:param etid:
:return:
""" """
sql = render_template( sql = render_template(
"/".join([self.template_path, self._PROPERTIES_SQL]), "/".join([self.template_path, self._PROPERTIES_SQL]),
@@ -332,21 +352,17 @@ class EventTriggerView(PGChildNodeView):
) )
status, res = self.conn.execute_dict(sql) status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the event trigger information.") gettext("Could not find the event trigger information."))
)
result = res['rows'][0] result = res['rows'][0]
result['is_sys_obj'] = (result['oid'] <= self.datlastsysoid) result['is_sys_obj'] = (result['oid'] <= self.datlastsysoid)
result = self._formatter(result) result = self._formatter(result)
return ajax_response( return True, result
response=result,
status=200
)
@check_precondition @check_precondition
def create(self, gid, sid, did): def create(self, gid, sid, did):
@@ -445,7 +461,7 @@ class EventTriggerView(PGChildNodeView):
# Most probably this is due to error # Most probably this is due to error
if not isinstance(sql, str): if not isinstance(sql, str):
return sql return sql
sql = sql.strip('\n').strip(' ')
if sql != "": if sql != "":
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
@@ -480,8 +496,31 @@ class EventTriggerView(PGChildNodeView):
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@staticmethod
def get_delete_data(cmd, etid, request_object):
"""
This function is used to get the data and cascade information.
:param cmd: Command
:param etid: Object ID
:param request_object: request object
:return:
"""
cascade = False
# Below will decide if it's simple drop or drop with cascade call
if cmd == 'delete':
# This is a cascade operation
cascade = True
if etid is None:
data = request_object.form if request_object.form else \
json.loads(request_object.data, encoding='utf-8')
else:
data = {'ids': [etid]}
return cascade, data
@check_precondition @check_precondition
def delete(self, gid, sid, did, etid=None): def delete(self, gid, sid, did, etid=None, only_sql=False):
""" """
This function will delete an existing event trigger object. This function will delete an existing event trigger object.
@@ -490,23 +529,13 @@ class EventTriggerView(PGChildNodeView):
sid: Server ID sid: Server ID
did: Database ID did: Database ID
etid: Event trigger ID etid: Event trigger ID
only_sql:
Returns: Returns:
""" """
# get the value of cascade and data
if self.cmd == 'delete': cascade, data = self.get_delete_data(self.cmd, etid, request)
# This is a cascade operation
cascade = True
else:
cascade = False
if etid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [etid]}
try: try:
for etid in data['ids']: for etid in data['ids']:
@@ -534,6 +563,11 @@ class EventTriggerView(PGChildNodeView):
"/".join([self.template_path, self._DELETE_SQL]), "/".join([self.template_path, self._DELETE_SQL]),
name=name, cascade=cascade name=name, cascade=cascade
) )
# Used for schema diff tool
if only_sql:
return sql
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -572,7 +606,7 @@ class EventTriggerView(PGChildNodeView):
# Most probably this is due to error # Most probably this is due to error
if not isinstance(sql, str): if not isinstance(sql, str):
return sql return sql
sql = sql.strip('\n').strip(' ')
sql = re.sub('\n{2,}', '\n\n', sql) sql = re.sub('\n{2,}', '\n\n', sql)
if sql == '': if sql == '':
sql = "--modified SQL" sql = "--modified SQL"
@@ -657,10 +691,10 @@ class EventTriggerView(PGChildNodeView):
"/".join([self.template_path, self._GRANT_SQL]), "/".join([self.template_path, self._GRANT_SQL]),
data=data data=data
) )
return sql return sql.strip('\n').strip(' ')
@check_precondition @check_precondition
def sql(self, gid, sid, did, etid): def sql(self, gid, sid, did, etid, json_resp=True):
""" """
This function will generate sql to show in the sql pane for the This function will generate sql to show in the sql pane for the
selected event trigger node. selected event trigger node.
@@ -670,6 +704,7 @@ class EventTriggerView(PGChildNodeView):
sid: Server ID sid: Server ID
did: Database ID did: Database ID
etid: Event trigger ID etid: Event trigger ID
json_resp:
Returns: Returns:
@@ -722,6 +757,9 @@ class EventTriggerView(PGChildNodeView):
sql = sql_header + sql sql = sql_header + sql
sql = re.sub('\n{2,}', '\n\n', sql) sql = re.sub('\n{2,}', '\n\n', sql)
if not json_resp:
return sql
return ajax_response(response=sql) return ajax_response(response=sql)
@check_precondition @check_precondition
@@ -791,5 +829,62 @@ class EventTriggerView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the event triggers for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
last_system_oid = 0
if self.manager.db_info is not None and did in self.manager.db_info:
last_system_oid = (self.manager.db_info[did])['datlastsysoid']
sql = render_template(
"/".join([self.template_path, 'nodes.sql']),
datlastsysoid=last_system_oid,
showsysobj=self.blueprint.show_system_objects
)
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(did, row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs:
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql = self.get_sql(data=data, etid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did,
etid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, etid=oid,
json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, EventTriggerView, 'Database')
EventTriggerView.register_node_view(blueprint) EventTriggerView.register_node_view(blueprint)

View File

@@ -3,6 +3,9 @@
{% if (data.eventfunname and data.eventfunname != o_data.eventfunname) or {% if (data.eventfunname and data.eventfunname != o_data.eventfunname) or
(data.eventname and data.eventname != o_data.eventname) or (data.eventname and data.eventname != o_data.eventname) or
(data.when and data.when != o_data.when) %} (data.when and data.when != o_data.when) %}
-- WARNING:
-- We have found the difference in either of Trigger Function, Event or WHEN
-- so we need to drop the existing event trigger first and re-create it.
DROP EVENT TRIGGER IF EXISTS {{ conn|qtIdent(o_data.name) }}; DROP EVENT TRIGGER IF EXISTS {{ conn|qtIdent(o_data.name) }};
CREATE EVENT TRIGGER {{ conn|qtIdent(data.name) if data.name else conn|qtIdent(o_data.name) }} ON {{ data.eventname if data.eventname else o_data.eventname }} CREATE EVENT TRIGGER {{ conn|qtIdent(data.name) if data.name else conn|qtIdent(o_data.name) }} ON {{ data.eventname if data.eventname else o_data.eventname }}

View File

@@ -21,6 +21,8 @@ from pgadmin.utils.ajax import make_json_response, \
make_response as ajax_response, internal_server_error, gone make_response as ajax_response, internal_server_error, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class ExtensionModule(CollectionNodeModule): class ExtensionModule(CollectionNodeModule):
@@ -75,7 +77,7 @@ class ExtensionModule(CollectionNodeModule):
blueprint = ExtensionModule(__name__) blueprint = ExtensionModule(__name__)
class ExtensionView(PGChildNodeView): class ExtensionView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
This is a class for extension nodes which inherits the This is a class for extension nodes which inherits the
properties and methods from NodeView class and define properties and methods from NodeView class and define
@@ -173,7 +175,7 @@ class ExtensionView(PGChildNodeView):
for row in rset['rows']: for row in rset['rows']:
res.append( res.append(
self.blueprint.generate_browser_node( self.blueprint.generate_browser_node(
row['eid'], row['oid'],
did, did,
row['name'], row['name'],
'icon-extension' 'icon-extension'
@@ -199,7 +201,7 @@ class ExtensionView(PGChildNodeView):
for row in rset['rows']: for row in rset['rows']:
return make_json_response( return make_json_response(
data=self.blueprint.generate_browser_node( data=self.blueprint.generate_browser_node(
row['eid'], row['oid'],
did, did,
row['name'], row['name'],
'icon-extension' 'icon-extension'
@@ -214,23 +216,37 @@ class ExtensionView(PGChildNodeView):
""" """
Fetch the properties of a single extension and render in properties tab Fetch the properties of a single extension and render in properties tab
""" """
status, res = self._fetch_properties(did, eid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, did, eid):
"""
This function fetch the properties of the extension.
:param did:
:param eid:
:return:
"""
SQL = render_template("/".join( SQL = render_template("/".join(
[self.template_path, self._PROPERTIES_SQL]), eid=eid) [self.template_path, self._PROPERTIES_SQL]), eid=eid)
status, res = self.conn.execute_dict(SQL) status, res = self.conn.execute_dict(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the extension information.") gettext("Could not find the extension information.")
) )
res['rows'][0]['is_sys_obj'] = ( res['rows'][0]['is_sys_obj'] = (
res['rows'][0]['eid'] <= self.datlastsysoid) res['rows'][0]['oid'] <= self.datlastsysoid)
return ajax_response(
response=res['rows'][0], return True, res['rows'][0]
status=200
)
@check_precondition @check_precondition
def create(self, gid, sid, did): def create(self, gid, sid, did):
@@ -278,7 +294,7 @@ class ExtensionView(PGChildNodeView):
for row in rset['rows']: for row in rset['rows']:
return jsonify( return jsonify(
node=self.blueprint.generate_browser_node( node=self.blueprint.generate_browser_node(
row['eid'], row['oid'],
did, did,
row['name'], row['name'],
'icon-extension' 'icon-extension'
@@ -316,7 +332,7 @@ class ExtensionView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, eid=None): def delete(self, gid, sid, did, eid=None, only_sql=False):
""" """
This function will drop/drop cascade a extension object This function will drop/drop cascade a extension object
""" """
@@ -355,6 +371,11 @@ class ExtensionView(PGChildNodeView):
SQL = render_template("/".join( SQL = render_template("/".join(
[self.template_path, self._DELETE_SQL] [self.template_path, self._DELETE_SQL]
), name=name, cascade=cascade) ), name=name, cascade=cascade)
# Used for schema diff tool
if only_sql:
return SQL
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -452,7 +473,7 @@ class ExtensionView(PGChildNodeView):
) )
@check_precondition @check_precondition
def sql(self, gid, sid, did, eid): def sql(self, gid, sid, did, eid, json_resp=True):
""" """
This function will generate sql for the sql panel This function will generate sql for the sql panel
""" """
@@ -477,6 +498,9 @@ class ExtensionView(PGChildNodeView):
display_comments=True display_comments=True
) )
if not json_resp:
return SQL
return ajax_response(response=SQL) return ajax_response(response=SQL)
@check_precondition @check_precondition
@@ -515,6 +539,57 @@ class ExtensionView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the extensions for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
sql = render_template("/".join([self.template_path,
'properties.sql']))
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(did, row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql, name = self.getSQL(gid=gid, sid=sid, did=did, data=data,
eid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did,
eid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, eid=oid,
json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, ExtensionView, 'Database')
# Register and add ExtensionView as blueprint # Register and add ExtensionView as blueprint
ExtensionView.register_node_view(blueprint) ExtensionView.register_node_view(blueprint)

View File

@@ -4,5 +4,5 @@ SELECT x.extname from pg_extension x
WHERE x.oid = {{ eid }}::oid WHERE x.oid = {{ eid }}::oid
{% endif %} {% endif %}
{% if name %} {% if name %}
DROP EXTENSION {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %} DROP EXTENSION {{ conn|qtIdent(name) }}{% if cascade %} CASCADE{% endif %};
{% endif %} {% endif %}

View File

@@ -1,6 +1,6 @@
{#===================Fetch properties of each extension by name or oid===================#} {#===================Fetch properties of each extension by name or oid===================#}
SELECT SELECT
x.oid AS eid, pg_get_userbyid(extowner) AS owner, x.oid, pg_get_userbyid(extowner) AS owner,
x.extname AS name, n.nspname AS schema, x.extname AS name, n.nspname AS schema,
x.extrelocatable AS relocatable, x.extversion AS version, x.extrelocatable AS relocatable, x.extversion AS version,
e.comment e.comment

View File

@@ -23,6 +23,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class ForeignDataWrapperModule(CollectionNodeModule): class ForeignDataWrapperModule(CollectionNodeModule):
@@ -98,7 +100,7 @@ class ForeignDataWrapperModule(CollectionNodeModule):
blueprint = ForeignDataWrapperModule(__name__) blueprint = ForeignDataWrapperModule(__name__)
class ForeignDataWrapperView(PGChildNodeView): class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
class ForeignDataWrapperView(PGChildNodeView) class ForeignDataWrapperView(PGChildNodeView)
@@ -196,6 +198,8 @@ class ForeignDataWrapperView(PGChildNodeView):
'get_validators': [{}, {'get': 'get_validators'}] 'get_validators': [{}, {'get': 'get_validators'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'fdwhandler', 'fdwvalidator']
def check_precondition(f): def check_precondition(f):
""" """
This function will behave as a decorator which will checks This function will behave as a decorator which will checks
@@ -280,7 +284,7 @@ class ForeignDataWrapperView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
res.append( res.append(
self.blueprint.generate_browser_node( self.blueprint.generate_browser_node(
row['fdwoid'], row['oid'],
did, did,
row['name'], row['name'],
icon="icon-foreign_data_wrapper" icon="icon-foreign_data_wrapper"
@@ -312,7 +316,7 @@ class ForeignDataWrapperView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
return make_json_response( return make_json_response(
data=self.blueprint.generate_browser_node( data=self.blueprint.generate_browser_node(
row['fdwoid'], row['oid'],
did, did,
row['name'], row['name'],
icon="icon-foreign_data_wrapper" icon="icon-foreign_data_wrapper"
@@ -335,23 +339,40 @@ class ForeignDataWrapperView(PGChildNodeView):
did: Database ID did: Database ID
fid: foreign data wrapper ID fid: foreign data wrapper ID
""" """
status, res = self._fetch_properties(fid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, fid):
"""
This function fetch the properties of the FDW.
:param fid:
:return:
"""
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]), self._PROPERTIES_SQL]),
fid=fid, conn=self.conn fid=fid, conn=self.conn
) )
status, res = self.conn.execute_dict(sql) status, res = self.conn.execute_dict(sql)
status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the foreign data" gettext("Could not find the foreign data"
" wrapper information.") " wrapper information.")
) )
res['rows'][0]['is_sys_obj'] = ( res['rows'][0]['is_sys_obj'] = (
res['rows'][0]['fdwoid'] <= self.datlastsysoid) res['rows'][0]['oid'] <= self.datlastsysoid)
if res['rows'][0]['fdwoptions'] is not None: if res['rows'][0]['fdwoptions'] is not None:
res['rows'][0]['fdwoptions'] = tokenize_options( res['rows'][0]['fdwoptions'] = tokenize_options(
@@ -362,9 +383,10 @@ class ForeignDataWrapperView(PGChildNodeView):
sql = render_template("/".join([self.template_path, self._ACL_SQL]), sql = render_template("/".join([self.template_path, self._ACL_SQL]),
fid=fid fid=fid
) )
status, fdw_acl_res = self.conn.execute_dict(sql) status, fdw_acl_res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=fdw_acl_res) return False, internal_server_error(errormsg=fdw_acl_res)
for row in fdw_acl_res['rows']: for row in fdw_acl_res['rows']:
privilege = parse_priv_from_db(row) privilege = parse_priv_from_db(row)
@@ -373,10 +395,7 @@ class ForeignDataWrapperView(PGChildNodeView):
else: else:
res['rows'][0][row['deftype']] = [privilege] res['rows'][0][row['deftype']] = [privilege]
return ajax_response( return True, res['rows'][0]
response=res['rows'][0],
status=200
)
@check_precondition @check_precondition
def create(self, gid, sid, did): def create(self, gid, sid, did):
@@ -438,7 +457,7 @@ class ForeignDataWrapperView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
return jsonify( return jsonify(
node=self.blueprint.generate_browser_node( node=self.blueprint.generate_browser_node(
row['fdwoid'], row['oid'],
did, did,
row['name'], row['name'],
icon='icon-foreign_data_wrapper' icon='icon-foreign_data_wrapper'
@@ -484,8 +503,31 @@ class ForeignDataWrapperView(PGChildNodeView):
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@staticmethod
def get_delete_data(cmd, fid, request_object):
"""
This function is used to get the data and cascade information.
:param cmd: Command
:param fid: Object ID
:param request_object: request object
:return:
"""
cascade = False
# Below will decide if it's simple drop or drop with cascade call
if cmd == 'delete':
# This is a cascade operation
cascade = True
if fid is None:
data = request_object.form if request_object.form else \
json.loads(request_object.data, encoding='utf-8')
else:
data = {'ids': [fid]}
return cascade, data
@check_precondition @check_precondition
def delete(self, gid, sid, did, fid=None): def delete(self, gid, sid, did, fid=None, only_sql=False):
""" """
This function will delete the selected foreign data wrapper node. This function will delete the selected foreign data wrapper node.
@@ -494,19 +536,10 @@ class ForeignDataWrapperView(PGChildNodeView):
sid: Server ID sid: Server ID
did: Database ID did: Database ID
fid: foreign data wrapper ID fid: foreign data wrapper ID
only_sql:
""" """
if fid is None: # get the value of cascade and data
data = request.form if request.form else json.loads( cascade, data = self.get_delete_data(self.cmd, fid, request)
request.data, encoding='utf-8'
)
else:
data = {'ids': [fid]}
if self.cmd == 'delete':
# This is a cascade operation
cascade = True
else:
cascade = False
for fid in data['ids']: for fid in data['ids']:
try: try:
@@ -537,6 +570,11 @@ class ForeignDataWrapperView(PGChildNodeView):
name=name, name=name,
cascade=cascade, cascade=cascade,
conn=self.conn) conn=self.conn)
# Used for schema diff tool
if only_sql:
return sql
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -717,14 +755,15 @@ class ForeignDataWrapperView(PGChildNodeView):
is_valid_changed_options=is_valid_changed_options, is_valid_changed_options=is_valid_changed_options,
conn=self.conn conn=self.conn
) )
return sql, data['name'] if 'name' in data else old_data['name'] return sql.strip('\n'), \
data['name'] if 'name' in data else old_data['name']
else: else:
sql = self._get_create_sql(data) sql = self._get_create_sql(data)
return sql, data['name'] return sql.strip('\n'), data['name']
@check_precondition @check_precondition
def sql(self, gid, sid, did, fid): def sql(self, gid, sid, did, fid, json_resp=True):
""" """
This function will generate sql to show it in sql pane This function will generate sql to show it in sql pane
for the selected foreign data wrapper node. for the selected foreign data wrapper node.
@@ -734,6 +773,7 @@ class ForeignDataWrapperView(PGChildNodeView):
sid: Server ID sid: Server ID
did: Database ID did: Database ID
fid: Foreign data wrapper ID fid: Foreign data wrapper ID
json_resp:
""" """
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]), self._PROPERTIES_SQL]),
@@ -795,6 +835,9 @@ class ForeignDataWrapperView(PGChildNodeView):
sql = sql_header + sql sql = sql_header + sql
if not json_resp:
return sql.strip('\n')
return ajax_response(response=sql.strip('\n')) return ajax_response(response=sql.strip('\n'))
@check_precondition @check_precondition
@@ -896,5 +939,56 @@ class ForeignDataWrapperView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the FDWs for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
sql = render_template("/".join([self.template_path,
'properties.sql']))
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql, name = self.get_sql(gid=gid, sid=sid, did=did, data=data,
fid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did,
fid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, fid=oid,
json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, ForeignDataWrapperView, 'Database')
ForeignDataWrapperView.register_node_view(blueprint) ForeignDataWrapperView.register_node_view(blueprint)

View File

@@ -23,6 +23,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class ForeignServerModule(CollectionNodeModule): class ForeignServerModule(CollectionNodeModule):
@@ -98,7 +100,7 @@ class ForeignServerModule(CollectionNodeModule):
blueprint = ForeignServerModule(__name__) blueprint = ForeignServerModule(__name__)
class ForeignServerView(PGChildNodeView): class ForeignServerView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
class ForeignServerView(PGChildNodeView) class ForeignServerView(PGChildNodeView)
@@ -187,6 +189,8 @@ class ForeignServerView(PGChildNodeView):
'dependent': [{'get': 'dependents'}] 'dependent': [{'get': 'dependents'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'fdwid']
def check_precondition(f): def check_precondition(f):
""" """
This function will behave as a decorator which will checks This function will behave as a decorator which will checks
@@ -269,7 +273,7 @@ class ForeignServerView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
res.append( res.append(
self.blueprint.generate_browser_node( self.blueprint.generate_browser_node(
row['fsrvid'], row['oid'],
fid, fid,
row['name'], row['name'],
icon="icon-foreign_server" icon="icon-foreign_server"
@@ -305,7 +309,7 @@ class ForeignServerView(PGChildNodeView):
return make_json_response( return make_json_response(
data=self.blueprint.generate_browser_node( data=self.blueprint.generate_browser_node(
row['fsrvid'], row['oid'],
fid, fid,
row['name'], row['name'],
icon="icon-foreign_server" icon="icon-foreign_server"
@@ -328,22 +332,36 @@ class ForeignServerView(PGChildNodeView):
fid: foreign data wrapper ID fid: foreign data wrapper ID
fsid: foreign server ID fsid: foreign server ID
""" """
status, res = self._fetch_properties(fsid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, fsid):
"""
This function fetch the properties of the Foreign server.
:param fsid:
:return:
"""
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]), self._PROPERTIES_SQL]),
fsid=fsid, conn=self.conn) fsid=fsid, conn=self.conn)
status, res = self.conn.execute_dict(sql)
status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the foreign server information.") gettext("Could not find the foreign server information.")
) )
res['rows'][0]['is_sys_obj'] = ( res['rows'][0]['is_sys_obj'] = (
res['rows'][0]['fsrvid'] <= self.datlastsysoid) res['rows'][0]['oid'] <= self.datlastsysoid)
if res['rows'][0]['fsrvoptions'] is not None: if res['rows'][0]['fsrvoptions'] is not None:
res['rows'][0]['fsrvoptions'] = tokenize_options( res['rows'][0]['fsrvoptions'] = tokenize_options(
@@ -354,9 +372,8 @@ class ForeignServerView(PGChildNodeView):
fsid=fsid fsid=fsid
) )
status, fs_rv_acl_res = self.conn.execute_dict(sql) status, fs_rv_acl_res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=fs_rv_acl_res) return False, internal_server_error(errormsg=fs_rv_acl_res)
for row in fs_rv_acl_res['rows']: for row in fs_rv_acl_res['rows']:
privilege = parse_priv_from_db(row) privilege = parse_priv_from_db(row)
@@ -365,10 +382,7 @@ class ForeignServerView(PGChildNodeView):
else: else:
res['rows'][0][row['deftype']] = [privilege] res['rows'][0][row['deftype']] = [privilege]
return ajax_response( return True, res['rows'][0]
response=res['rows'][0],
status=200
)
@check_precondition @check_precondition
def create(self, gid, sid, did, fid): def create(self, gid, sid, did, fid):
@@ -439,7 +453,7 @@ class ForeignServerView(PGChildNodeView):
return jsonify( return jsonify(
node=self.blueprint.generate_browser_node( node=self.blueprint.generate_browser_node(
r_set['rows'][0]['fsrvid'], r_set['rows'][0]['oid'],
fid, fid,
r_set['rows'][0]['name'], r_set['rows'][0]['name'],
icon="icon-foreign_server" icon="icon-foreign_server"
@@ -488,8 +502,31 @@ class ForeignServerView(PGChildNodeView):
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@staticmethod
def get_delete_data(cmd, fsid, request_object):
"""
This function is used to get the data and cascade information.
:param cmd: Command
:param fsid: Object ID
:param request_object: request object
:return:
"""
cascade = False
# Below will decide if it's simple drop or drop with cascade call
if cmd == 'delete':
# This is a cascade operation
cascade = True
if fsid is None:
data = request_object.form if request_object.form else \
json.loads(request_object.data, encoding='utf-8')
else:
data = {'ids': [fsid]}
return cascade, data
@check_precondition @check_precondition
def delete(self, gid, sid, did, fid, fsid=None): def delete(self, gid, sid, did, fid, fsid=None, only_sql=False):
""" """
This function will delete the selected foreign server node. This function will delete the selected foreign server node.
@@ -499,20 +536,10 @@ class ForeignServerView(PGChildNodeView):
did: Database ID did: Database ID
fid: foreign data wrapper ID fid: foreign data wrapper ID
fsid: foreign server ID fsid: foreign server ID
only_sql:
""" """
# get the value of cascade and data
if fsid is None: cascade, data = self.get_delete_data(self.cmd, fsid, request)
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [fsid]}
if self.cmd == 'delete':
# This is a cascade operation
cascade = True
else:
cascade = False
try: try:
for fsid in data['ids']: for fsid in data['ids']:
@@ -542,6 +569,11 @@ class ForeignServerView(PGChildNodeView):
self._DELETE_SQL]), self._DELETE_SQL]),
name=name, cascade=cascade, name=name, cascade=cascade,
conn=self.conn) conn=self.conn)
# Used for schema diff tool
if only_sql:
return sql.strip('\n')
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -674,7 +706,8 @@ class ForeignServerView(PGChildNodeView):
is_valid_changed_options=is_valid_changed_options, is_valid_changed_options=is_valid_changed_options,
conn=self.conn conn=self.conn
) )
return sql, data['name'] if 'name' in data else old_data['name'] return sql.strip('\n'), \
data['name'] if 'name' in data else old_data['name']
else: else:
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]), self._PROPERTIES_SQL]),
@@ -704,7 +737,7 @@ class ForeignServerView(PGChildNodeView):
return sql, data['name'] return sql, data['name']
@check_precondition @check_precondition
def sql(self, gid, sid, did, fid, fsid): def sql(self, gid, sid, did, fid, fsid, json_resp=True):
""" """
This function will generate sql to show it in sql pane for the This function will generate sql to show it in sql pane for the
selected foreign server node. selected foreign server node.
@@ -715,6 +748,7 @@ class ForeignServerView(PGChildNodeView):
did: Database ID did: Database ID
fid: Foreign data wrapper ID fid: Foreign data wrapper ID
fsid: Foreign server ID fsid: Foreign server ID
json_resp:
""" """
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
@@ -728,6 +762,9 @@ class ForeignServerView(PGChildNodeView):
gettext("Could not find the foreign server information.") gettext("Could not find the foreign server information.")
) )
if fid is None and 'fdwid' in res['rows'][0]:
fid = res['rows'][0]['fdwid']
is_valid_options = False is_valid_options = False
if res['rows'][0]['fsrvoptions'] is not None: if res['rows'][0]['fsrvoptions'] is not None:
res['rows'][0]['fsrvoptions'] = tokenize_options( res['rows'][0]['fsrvoptions'] = tokenize_options(
@@ -782,6 +819,9 @@ class ForeignServerView(PGChildNodeView):
sql = sql_header + sql sql = sql_header + sql
if not json_resp:
return sql.strip('\n')
return ajax_response(response=sql.strip('\n')) return ajax_response(response=sql.strip('\n'))
@check_precondition @check_precondition
@@ -836,5 +876,57 @@ class ForeignServerView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the FDWs for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
sql = render_template("/".join([self.template_path,
'properties.sql']))
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
fdw_id = kwargs.get('fdwid')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql, name = self.get_sql(gid=gid, sid=sid, did=did, data=data,
fid=fdw_id, fsid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, fid=fdw_id,
fsid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, fid=fdw_id,
fsid=oid, json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, ForeignServerView, 'Database')
ForeignServerView.register_node_view(blueprint) ForeignServerView.register_node_view(blueprint)

View File

@@ -101,7 +101,7 @@ define('pgadmin.node.foreign_server', [
// Defining model for foreign server node // Defining model for foreign server node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'fsrvid', idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
fsrvtype: undefined, fsrvtype: undefined,
@@ -135,7 +135,7 @@ define('pgadmin.node.foreign_server', [
); );
}, },
},{ },{
id: 'fsrvid', label: gettext('OID'), cell: 'string', id: 'oid', label: gettext('OID'), cell: 'string',
type: 'text', mode: ['properties'], type: 'text', mode: ['properties'],
},{ },{
id: 'fsrvowner', label: gettext('Owner'), type: 'text', id: 'fsrvowner', label: gettext('Owner'), type: 'text',

View File

@@ -5,8 +5,8 @@ FROM pg_foreign_data_wrapper fdw
LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass) LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
WHERE fdw.oid={{fdwid}}::oid WHERE fdw.oid={{fdwid}}::oid
{% else %} {% else %}
SELECT srv.oid as fsrvid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description, SELECT srv.oid, srvname as name, srvfdw as fdwid, srvtype as fsrvtype, srvversion as fsrvversion,
array_to_string(srvoptions, ',') AS fsrvoptions, fdw.fdwname as fdwname, description, array_to_string(srvoptions, ',') AS fsrvoptions,
pg_get_userbyid(srvowner) as fsrvowner, array_to_string(srvacl::text[], ', ') as acl pg_get_userbyid(srvowner) as fsrvowner, array_to_string(srvacl::text[], ', ') as acl
FROM pg_foreign_server srv FROM pg_foreign_server srv
LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw

View File

@@ -6,7 +6,7 @@ FROM pg_foreign_data_wrapper fdw
LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass) LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
WHERE fdw.oid={{fdwid}}::oid WHERE fdw.oid={{fdwid}}::oid
{% else %} {% else %}
SELECT srv.oid as fsrvid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description, SELECT srv.oid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description,
array_to_string(srvoptions, ',') AS fsrvoptions, array_to_string(srvoptions, ',') AS fsrvoptions,
pg_get_userbyid(srvowner) as fsrvowner, array_to_string(srvacl::text[], ', ') as acl pg_get_userbyid(srvowner) as fsrvowner, array_to_string(srvacl::text[], ', ') as acl
FROM pg_foreign_server srv FROM pg_foreign_server srv

View File

@@ -1,10 +1,37 @@
{% import 'macros/privilege.macros' as PRIVILEGE %} {% import 'macros/privilege.macros' as PRIVILEGE %}
{% if data %} {% if data %}
{% if (data.fsrvtype is defined and data.fsrvtype != o_data.fsrvtype) or (data.fdwname is defined and data.fdwname != o_data.fdwname) %}
{% set fsrvtype = o_data.fsrvtype %}
{% set fdwname = o_data.fdwname %}
{% if data.fsrvtype is defined %}
{% set fsrvtype = data.fsrvtype %}
{% endif %}
{% if data.fdwname is defined %}
{% set fdwname = data.fdwname %}
{% endif %}
-- WARNING:
-- We have found the difference in SERVER TYPE OR FOREIGN DATA WRAPPER
-- so we need to drop the existing foreign server first and re-create it.
DROP SERVER {{ conn|qtIdent(o_data.name) }};
CREATE SERVER {{ conn|qtIdent(o_data.name) }}{% if data.fsrvtype or o_data.fsrvtype %}
TYPE {{ fsrvtype|qtLiteral }}{% endif %}{% if o_data.fsrvversion %}
VERSION {{ o_data.fsrvversion|qtLiteral }}{%-endif %}{% if o_data.fdwname %}
FOREIGN DATA WRAPPER {{ conn|qtIdent(fdwname) }}{% endif %}{% if o_data.fsrvoptions %}
OPTIONS ({% for variable in o_data.fsrvoptions %}{% if loop.index != 1 %}, {% endif %}
{{ conn|qtIdent(variable.fsrvoption) }} {{ variable.fsrvvalue|qtLiteral }}{% endfor %}){% endif %};
{% else %}
{# ============= Update foreign server name ============= #} {# ============= Update foreign server name ============= #}
{% if data.name != o_data.name %} {% if data.name != o_data.name %}
ALTER SERVER {{ conn|qtIdent(o_data.name) }} ALTER SERVER {{ conn|qtIdent(o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }}; RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{% endif %} {% endif %}
{# ============= Update foreign server owner ============= #} {# ============= Update foreign server owner ============= #}
{% if data.fsrvowner and data.fsrvowner != o_data.fsrvowner %} {% if data.fsrvowner and data.fsrvowner != o_data.fsrvowner %}
@@ -13,7 +40,7 @@ ALTER SERVER {{ conn|qtIdent(data.name) }}
{% endif %} {% endif %}
{# ============= Update foreign server version ============= #} {# ============= Update foreign server version ============= #}
{% if data.fsrvversion and data.fsrvversion != o_data.fsrvversion %} {% if data.fsrvversion is defined and data.fsrvversion != o_data.fsrvversion %}
ALTER SERVER {{ conn|qtIdent(data.name) }} ALTER SERVER {{ conn|qtIdent(data.name) }}
VERSION {{ data.fsrvversion|qtLiteral }}; VERSION {{ data.fsrvversion|qtLiteral }};

View File

@@ -23,6 +23,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class UserMappingModule(CollectionNodeModule): class UserMappingModule(CollectionNodeModule):
@@ -114,7 +116,7 @@ class UserMappingModule(CollectionNodeModule):
blueprint = UserMappingModule(__name__) blueprint = UserMappingModule(__name__)
class UserMappingView(PGChildNodeView): class UserMappingView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
class UserMappingView(PGChildNodeView) class UserMappingView(PGChildNodeView)
@@ -204,6 +206,8 @@ class UserMappingView(PGChildNodeView):
'dependent': [{'get': 'dependents'}] 'dependent': [{'get': 'dependents'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'fdwid', 'fsid']
def check_precondition(f): def check_precondition(f):
""" """
This function will behave as a decorator which will checks This function will behave as a decorator which will checks
@@ -287,7 +291,7 @@ class UserMappingView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
res.append( res.append(
self.blueprint.generate_browser_node( self.blueprint.generate_browser_node(
row['um_oid'], row['oid'],
fsid, fsid,
row['name'], row['name'],
icon="icon-user_mapping" icon="icon-user_mapping"
@@ -322,7 +326,7 @@ class UserMappingView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
return make_json_response( return make_json_response(
data=self.blueprint.generate_browser_node( data=self.blueprint.generate_browser_node(
row['um_oid'], row['oid'],
fsid, fsid,
row['name'], row['name'],
icon="icon-user_mapping" icon="icon-user_mapping"
@@ -346,32 +350,44 @@ class UserMappingView(PGChildNodeView):
fsid: Foreign server ID fsid: Foreign server ID
umid: User mapping ID umid: User mapping ID
""" """
status, res = self._fetch_properties(umid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, umid):
"""
This function fetch the properties of the User Mapping.
:param umid:
:return:
"""
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]), self._PROPERTIES_SQL]),
umid=umid, conn=self.conn) umid=umid, conn=self.conn)
status, res = self.conn.execute_dict(sql)
status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the user mapping information.") gettext("Could not find the user mapping information.")
) )
res['rows'][0]['is_sys_obj'] = ( res['rows'][0]['is_sys_obj'] = (
res['rows'][0]['um_oid'] <= self.datlastsysoid) res['rows'][0]['oid'] <= self.datlastsysoid)
if res['rows'][0]['umoptions'] is not None: if res['rows'][0]['umoptions'] is not None:
res['rows'][0]['umoptions'] = tokenize_options( res['rows'][0]['umoptions'] = tokenize_options(
res['rows'][0]['umoptions'], res['rows'][0]['umoptions'],
'umoption', 'umvalue' 'umoption', 'umvalue'
) )
return ajax_response(
response=res['rows'][0], return True, res['rows'][0]
status=200
)
@check_precondition @check_precondition
def create(self, gid, sid, did, fid, fsid): def create(self, gid, sid, did, fid, fsid):
@@ -443,7 +459,7 @@ class UserMappingView(PGChildNodeView):
for row in r_set['rows']: for row in r_set['rows']:
return jsonify( return jsonify(
node=self.blueprint.generate_browser_node( node=self.blueprint.generate_browser_node(
row['um_oid'], row['oid'],
fsid, fsid,
row['name'], row['name'],
icon='icon-user_mapping' icon='icon-user_mapping'
@@ -492,8 +508,31 @@ class UserMappingView(PGChildNodeView):
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@staticmethod
def get_delete_data(cmd, umid, request_object):
"""
This function is used to get the data and cascade information.
:param cmd: Command
:param umid: Object ID
:param request_object: request object
:return:
"""
cascade = False
# Below will decide if it's simple drop or drop with cascade call
if cmd == 'delete':
# This is a cascade operation
cascade = True
if umid is None:
data = request_object.form if request_object.form else \
json.loads(request_object.data, encoding='utf-8')
else:
data = {'ids': [umid]}
return cascade, data
@check_precondition @check_precondition
def delete(self, gid, sid, did, fid, fsid, umid=None): def delete(self, gid, sid, did, fid, fsid, **kwargs):
""" """
This function will delete the selected user mapping node. This function will delete the selected user mapping node.
@@ -503,20 +542,15 @@ class UserMappingView(PGChildNodeView):
did: Database ID did: Database ID
fid: foreign data wrapper ID fid: foreign data wrapper ID
fsid: foreign server ID fsid: foreign server ID
umid: User mapping ID **kwargs:
"""
if umid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [umid]}
if self.cmd == 'delete': """
# This is a cascade operation
cascade = True umid = kwargs.get('umid', None)
else: only_sql = kwargs.get('only_sql', False)
cascade = False
# get the value of cascade and data
cascade, data = self.get_delete_data(self.cmd, umid, request)
try: try:
for umid in data['ids']: for umid in data['ids']:
@@ -564,6 +598,11 @@ class UserMappingView(PGChildNodeView):
self._DELETE_SQL]), self._DELETE_SQL]),
data=data, name=name, cascade=cascade, data=data, name=name, cascade=cascade,
conn=self.conn) conn=self.conn)
# Used for schema diff tool
if only_sql:
return sql
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -707,7 +746,7 @@ class UserMappingView(PGChildNodeView):
return sql, data['name'] return sql, data['name']
@check_precondition @check_precondition
def sql(self, gid, sid, did, fid, fsid, umid): def sql(self, gid, sid, did, fid, fsid, **kwargs):
""" """
This function will generate sql to show it in sql pane for This function will generate sql to show it in sql pane for
the selected user mapping node. the selected user mapping node.
@@ -718,8 +757,10 @@ class UserMappingView(PGChildNodeView):
did: Database ID did: Database ID
fid: Foreign data wrapper ID fid: Foreign data wrapper ID
fsid: Foreign server ID fsid: Foreign server ID
umid: User mapping ID kwargs:
""" """
umid = kwargs.get('umid')
json_resp = kwargs.get('json_resp', True)
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]), self._PROPERTIES_SQL]),
@@ -732,6 +773,9 @@ class UserMappingView(PGChildNodeView):
gettext("Could not find the user mapping information.") gettext("Could not find the user mapping information.")
) )
if fsid is None and 'fsid' in res['rows'][0]:
fsid = res['rows'][0]['fsid']
is_valid_options = False is_valid_options = False
if res['rows'][0]['umoptions'] is not None: if res['rows'][0]['umoptions'] is not None:
res['rows'][0]['umoptions'] = tokenize_options( res['rows'][0]['umoptions'] = tokenize_options(
@@ -767,6 +811,9 @@ class UserMappingView(PGChildNodeView):
sql = sql_header + sql sql = sql_header + sql
if not json_resp:
return sql.strip('\n')
return ajax_response(response=sql.strip('\n')) return ajax_response(response=sql.strip('\n'))
@check_precondition @check_precondition
@@ -810,5 +857,57 @@ class UserMappingView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the FDWs for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
sql = render_template("/".join([self.template_path,
'properties.sql']))
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs:
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
fid = kwargs.get('fdwid')
fsid = kwargs.get('fsid')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql, name = self.get_sql(data=data, fsid=fsid, umid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, fid=fid,
fsid=fsid, umid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, fid=fid, fsid=fsid,
umid=oid, json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, UserMappingView, 'Database')
UserMappingView.register_node_view(blueprint) UserMappingView.register_node_view(blueprint)

View File

@@ -5,5 +5,5 @@ SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_dat
{% endif %} {% endif %}
{# ============= Drop/Delete cascade user mapping ============= #} {# ============= Drop/Delete cascade user mapping ============= #}
{% if name and data %} {% if name and data %}
DROP USER MAPPING FOR {% if data.name == "CURRENT_USER" or data.name == "PUBLIC" %}{{ data.name }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} SERVER {{ conn|qtIdent(name) }} DROP USER MAPPING FOR {% if data.name == "CURRENT_USER" or data.name == "PUBLIC" %}{{ data.name }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} SERVER {{ conn|qtIdent(name) }};
{% endif %} {% endif %}

View File

@@ -4,10 +4,15 @@ SELECT srv.oid as fsrvid, srvname as name
FROM pg_foreign_server srv FROM pg_foreign_server srv
LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass) LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
WHERE srv.oid = {{fserid}}::oid WHERE srv.oid = {{fserid}}::oid
{% endif %} {% elif fsid or umid %}
{% if fsid or umid %} SELECT u.umid AS oid, u.usename AS name, u.srvid AS fsid, array_to_string(u.umoptions, ',') AS umoptions, fs.srvfdw AS fdwid
SELECT u.umid AS um_oid, u.usename as name, array_to_string(u.umoptions, ',') AS umoptions
FROM pg_user_mappings u FROM pg_user_mappings u
LEFT JOIN pg_foreign_server fs ON fs.oid = u.srvid
{% if fsid %} WHERE u.srvid = {{fsid}}::oid {% endif %} {% if umid %} WHERE u.umid= {{umid}}::oid {% endif %} {% if fsid %} WHERE u.srvid = {{fsid}}::oid {% endif %} {% if umid %} WHERE u.umid= {{umid}}::oid {% endif %}
ORDER BY 2; ORDER BY 2;
{% else %}
SELECT u.umid AS oid, u.usename AS name, u.srvid AS fsid, array_to_string(u.umoptions, ',') AS umoptions, fs.srvfdw AS fdwid
FROM pg_user_mappings u
LEFT JOIN pg_foreign_server fs ON fs.oid = u.srvid
ORDER BY 2;
{% endif %} {% endif %}

View File

@@ -104,7 +104,7 @@ define('pgadmin.node.foreign_data_wrapper', [
// Defining model for foreign data wrapper node // Defining model for foreign data wrapper node
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'fdwoid', idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
fdwowner: undefined, fdwowner: undefined,
@@ -138,7 +138,7 @@ define('pgadmin.node.foreign_data_wrapper', [
); );
}, },
},{ },{
id: 'fdwoid', label: gettext('OID'), cell: 'string', id: 'oid', label: gettext('OID'), cell: 'string',
type: 'text', mode: ['properties'], type: 'text', mode: ['properties'],
},{ },{
id: 'fdwowner', label: gettext('Owner'), type: 'text', id: 'fdwowner', label: gettext('Owner'), type: 'text',

View File

@@ -1,5 +1,5 @@
{# ============= Get all the properties of foreign data wrapper ============= #} {# ============= Get all the properties of foreign data wrapper ============= #}
SELECT fdw.oid as fdwoid, fdwname as name, fdwhandler, fdwvalidator, description, SELECT fdw.oid, fdwname as name, fdwhandler, fdwvalidator, description,
array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner, array_to_string(fdwacl::text[], ', ') as acl, array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner, array_to_string(fdwacl::text[], ', ') as acl,
CASE CASE
-- EPAS in redwood mode, concatenation of a string with NULL results as the original string -- EPAS in redwood mode, concatenation of a string with NULL results as the original string

View File

@@ -18,7 +18,7 @@ ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
VALIDATOR {{ data.fdwvalue }}; VALIDATOR {{ data.fdwvalue }};
{% endif %} {% endif %}
{% if data.fdwvalue == '' and data.fdwvalue != o_data.fdwvalue %} {% if (data.fdwvalue == '' or data.fdwvalue == None) and data.fdwvalue != o_data.fdwvalue %}
ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }} ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
NO VALIDATOR; NO VALIDATOR;
@@ -29,7 +29,7 @@ ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
HANDLER {{ data.fdwhan }}; HANDLER {{ data.fdwhan }};
{% endif %} {% endif %}
{% if data.fdwhan == '' and data.fdwhan != o_data.fdwhan %} {% if (data.fdwhan == '' or data.fdwhan == None) and data.fdwhan != o_data.fdwhan %}
ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }} ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
NO HANDLER; NO HANDLER;

View File

@@ -1,5 +1,5 @@
{# ============= Get all the properties of foreign data wrapper ============= #} {# ============= Get all the properties of foreign data wrapper ============= #}
SELECT fdw.oid as fdwoid, fdwname as name, fdwhandler, fdwvalidator, description, SELECT fdw.oid, fdwname as name, fdwhandler, fdwvalidator, description,
array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner, array_to_string(fdwacl::text[], ', ') as acl, array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner, array_to_string(fdwacl::text[], ', ') as acl,
CASE CASE
-- EPAS in redwood mode, concatenation of a string with NULL results as the original string -- EPAS in redwood mode, concatenation of a string with NULL results as the original string

View File

@@ -18,7 +18,7 @@ ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
VALIDATOR {{ data.fdwvalue }}; VALIDATOR {{ data.fdwvalue }};
{% endif %} {% endif %}
{% if data.fdwvalue == '' and data.fdwvalue != o_data.fdwvalue %} {% if (data.fdwvalue == '' or data.fdwvalue == None) and data.fdwvalue != o_data.fdwvalue %}
ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }} ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
NO VALIDATOR; NO VALIDATOR;
@@ -29,7 +29,7 @@ ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
HANDLER {{ data.fdwhan }}; HANDLER {{ data.fdwhan }};
{% endif %} {% endif %}
{% if data.fdwhan == '' and data.fdwhan != o_data.fdwhan %} {% if (data.fdwhan == '' or data.fdwhan == None) and data.fdwhan != o_data.fdwhan %}
ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }} ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
NO HANDLER; NO HANDLER;

View File

@@ -23,6 +23,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
class LanguageModule(CollectionNodeModule): class LanguageModule(CollectionNodeModule):
@@ -105,7 +107,7 @@ class LanguageModule(CollectionNodeModule):
blueprint = LanguageModule(__name__) blueprint = LanguageModule(__name__)
class LanguageView(PGChildNodeView): class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
""" """
class LanguageView(PGChildNodeView) class LanguageView(PGChildNodeView)
@@ -338,6 +340,22 @@ class LanguageView(PGChildNodeView):
did: Database ID did: Database ID
lid: Language ID lid: Language ID
""" """
status, res = self._fetch_properties(did, lid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, did, lid):
"""
This function fetch the properties of the extension.
:param did:
:param lid:
:return:
"""
sql = render_template( sql = render_template(
"/".join([self.template_path, self._PROPERTIES_SQL]), "/".join([self.template_path, self._PROPERTIES_SQL]),
lid=lid lid=lid
@@ -345,10 +363,10 @@ class LanguageView(PGChildNodeView):
status, res = self.conn.execute_dict(sql) status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0: if len(res['rows']) == 0:
return gone( return False, gone(
gettext("Could not find the language information.") gettext("Could not find the language information.")
) )
@@ -361,7 +379,7 @@ class LanguageView(PGChildNodeView):
) )
status, result = self.conn.execute_dict(sql) status, result = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=result) return False, internal_server_error(errormsg=result)
# if no acl found then by default add public # if no acl found then by default add public
if res['rows'][0]['acl'] is None: if res['rows'][0]['acl'] is None:
@@ -396,10 +414,7 @@ class LanguageView(PGChildNodeView):
res['rows'][0]['seclabels'] = seclabels res['rows'][0]['seclabels'] = seclabels
return ajax_response( return True, res['rows'][0]
response=res['rows'][0],
status=200
)
@check_precondition @check_precondition
def update(self, gid, sid, did, lid): def update(self, gid, sid, did, lid):
@@ -498,7 +513,7 @@ class LanguageView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, lid=None): def delete(self, gid, sid, did, lid=None, only_sql=False):
""" """
This function will drop the language object This function will drop the language object
@@ -507,6 +522,7 @@ class LanguageView(PGChildNodeView):
sid: Server ID sid: Server ID
did: Database ID did: Database ID
lid: Language ID lid: Language ID
only_sql:
""" """
if lid is None: if lid is None:
data = request.form if request.form else json.loads( data = request.form if request.form else json.loads(
@@ -538,8 +554,12 @@ class LanguageView(PGChildNodeView):
"/".join([self.template_path, self._DELETE_SQL]), "/".join([self.template_path, self._DELETE_SQL]),
lname=lname, cascade=cascade, conn=self.conn lname=lname, cascade=cascade, conn=self.conn
) )
status, res = self.conn.execute_scalar(sql)
# Used for schema diff tool
if only_sql:
return sql
status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
@@ -690,7 +710,7 @@ class LanguageView(PGChildNodeView):
) )
@check_precondition @check_precondition
def sql(self, gid, sid, did, lid): def sql(self, gid, sid, did, lid, json_resp=True):
""" """
This function will generate sql to show in the sql pane for the This function will generate sql to show in the sql pane for the
selected language node. selected language node.
@@ -700,6 +720,7 @@ class LanguageView(PGChildNodeView):
sid: Server ID sid: Server ID
did: Database ID did: Database ID
lid: Language ID lid: Language ID
json_resp:
""" """
sql = render_template( sql = render_template(
"/".join([self.template_path, self._PROPERTIES_SQL]), "/".join([self.template_path, self._PROPERTIES_SQL]),
@@ -755,6 +776,9 @@ class LanguageView(PGChildNodeView):
data=old_data, conn=self.conn data=old_data, conn=self.conn
) )
if not json_resp:
return sql.strip('\n')
return ajax_response(response=sql.strip('\n')) return ajax_response(response=sql.strip('\n'))
@check_precondition @check_precondition
@@ -793,5 +817,54 @@ class LanguageView(PGChildNodeView):
status=200 status=200
) )
@check_precondition
def fetch_objects_to_compare(self, sid, did):
"""
This function will fetch the list of all the event triggers for
specified database id.
:param sid: Server Id
:param did: Database Id
:return:
"""
res = dict()
sql = render_template("/".join([self.template_path,
'properties.sql']))
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
status, data = self._fetch_properties(did, row['oid'])
if status:
res[row['name']] = data
return res
def get_sql_from_diff(self, **kwargs):
"""
This function is used to get the DDL/DML statements.
:param kwargs:
:return:
"""
gid = kwargs.get('gid')
sid = kwargs.get('sid')
did = kwargs.get('did')
oid = kwargs.get('oid')
data = kwargs.get('data', None)
drop_sql = kwargs.get('drop_sql', False)
if data:
sql, name = self.get_sql(data=data, lid=oid)
else:
if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did,
lid=oid, only_sql=True)
else:
sql = self.sql(gid=gid, sid=sid, did=did, lid=oid,
json_resp=False)
return sql
SchemaDiffRegistry(blueprint.node_type, LanguageView, 'Database')
LanguageView.register_node_view(blueprint) LanguageView.register_node_view(blueprint)

View File

@@ -1,6 +1,28 @@
{% import 'macros/privilege.macros' as PRIVILEGE %} {% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/security.macros' as SECLABEL %} {% import 'macros/security.macros' as SECLABEL %}
{% if data %} {% if data %}
{# ============= Check for Schema Diff Tool ============= #}
{% if (data.trusted and data.trusted != o_data.trusted) or (data.lanproc and data.lanproc != o_data.lanproc) or (data.laninl and data.laninl != o_data.laninl) or (data.lanval and data.lanval != o_data.lanval) %}
-- WARNING:
-- We have found the difference in either of TRUSTED, HANDLER, INLINE or VALIDATOR,
-- so we need to drop the existing language first and re-create it.
DROP LANGUAGE {{ conn|qtIdent(o_data.name) }} CASCADE;
{% if data.trusted is defined %}{% set tmp_trusted = data.trusted %}{% else %}{% set tmp_trusted = o_data.trusted %}{% endif %}
{% if data.lanproc is defined %}{% set tmp_lanproc = data.lanproc %}{% else %}{% set tmp_lanproc = o_data.lanproc %}{% endif %}
{% if data.laninl is defined %}{% set tmp_laninl = data.laninl %}{% else %}{% set tmp_laninl = o_data.laninl %}{% endif %}
{% if data.lanval is defined %}{% set tmp_lanval = data.lanval %}{% else %}{% set tmp_lanval = o_data.lanval %}{% endif %}
CREATE{% if tmp_trusted %} TRUSTED{% endif %} PROCEDURAL LANGUAGE {{ conn|qtIdent(o_data.name) }}
{% if tmp_lanproc %}
HANDLER {{ conn|qtIdent(tmp_lanproc) }}
{% endif %}
{% if tmp_laninl %}
INLINE {{ conn|qtIdent(tmp_laninl) }}
{% endif %}
{% if tmp_lanval %}
VALIDATOR {{ conn|qtIdent(tmp_lanval) }}
{% endif %};
{% endif %}
{# ============= Update language name ============= #} {# ============= Update language name ============= #}
{% if data.name != o_data.name %} {% if data.name != o_data.name %}
ALTER LANGUAGE {{ conn|qtIdent(o_data.name) }} ALTER LANGUAGE {{ conn|qtIdent(o_data.name) }}

View File

@@ -701,10 +701,8 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
did: Database ID did: Database ID
scid: Schema ID scid: Schema ID
coid: Collation ID coid: Collation ID
diff_schema: Target Schema for schema diff
json_resp: True then return json response json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
@@ -720,9 +718,6 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
data = res['rows'][0] data = res['rows'][0]
if diff_schema:
data['schema'] = diff_schema
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
self._CREATE_SQL]), self._CREATE_SQL]),
data=data, conn=self.conn) data=data, conn=self.conn)
@@ -821,21 +816,15 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, data=data, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, data=data, scid=scid,
coid=oid) coid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, coid=oid, only_sql=True) scid=scid, coid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, coid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, coid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, coid=oid,
json_resp=False) json_resp=False)

View File

@@ -723,10 +723,8 @@ AND relkind != 'c'))"""
did: Database Id did: Database Id
scid: Schema Id scid: Schema Id
doid: Domain Id doid: Domain Id
diff_schema: Target Schema for schema diff
json_resp: True then return json response json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
@@ -742,9 +740,6 @@ AND relkind != 'c'))"""
data = res['rows'][0] data = res['rows'][0]
if diff_schema:
data['basensp'] = diff_schema
# Get Type Length and Precision # Get Type Length and Precision
data.update(self._parse_type(data['fulltype'])) data.update(self._parse_type(data['fulltype']))
@@ -954,12 +949,9 @@ AND relkind != 'c'))"""
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, scid=scid,
data=data, doid=oid, data=data, doid=oid,
is_schema_diff=True) is_schema_diff=True)
@@ -967,9 +959,6 @@ AND relkind != 'c'))"""
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, doid=oid, only_sql=True) scid=scid, doid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, doid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, doid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, doid=oid,
json_resp=False) json_resp=False)

View File

@@ -832,10 +832,8 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
did: Database Id did: Database Id
scid: Schema Id scid: Schema Id
foid: Foreign Table Id foid: Foreign Table Id
diff_schema: Target Schema for schema diff
json_resp: True then return json response json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
status, data = self._fetch_properties(gid, sid, did, scid, foid, status, data = self._fetch_properties(gid, sid, did, scid, foid,
@@ -846,9 +844,6 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
return gone( return gone(
gettext("The specified foreign table could not be found.")) gettext("The specified foreign table could not be found."))
if diff_schema:
data['basensp'] = diff_schema
col_data = [] col_data = []
for c in data['columns']: for c in data['columns']:
if ('inheritedfrom' not in c) or (c['inheritedfrom'] is None): if ('inheritedfrom' not in c) or (c['inheritedfrom'] is None):
@@ -1494,12 +1489,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
data=data, foid=oid, data=data, foid=oid,
is_schema_diff=True) is_schema_diff=True)
@@ -1507,9 +1499,6 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, foid=oid, only_sql=True) scid=scid, foid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, foid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, foid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, foid=oid,
json_resp=False) json_resp=False)

View File

@@ -205,6 +205,8 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
'compare': [{'get': 'compare'}, {'get': 'compare'}] 'compare': [{'get': 'compare'}, {'get': 'compare'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'schema']
def _init_(self, **kwargs): def _init_(self, **kwargs):
self.conn = None self.conn = None
self.template_path = None self.template_path = None
@@ -903,10 +905,8 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
:param did: database id :param did: database id
:param scid: schema id :param scid: schema id
:param cfgid: FTS Configuration id :param cfgid: FTS Configuration id
:param diff_schema: Target Schema for schema diff
:param json_resp: True then return json response :param json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
try: try:
@@ -932,22 +932,6 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
"FTS Configuration node.") "FTS Configuration node.")
) )
# Used for schema diff tool
if diff_schema:
data = {'schema': scid}
# Fetch schema name from schema oid
sql = render_template("/".join([self.template_path,
self._SCHEMA_SQL]),
data=data,
conn=self.conn,
)
status, schema = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=schema)
res = res.replace(schema, diff_schema)
if not json_resp: if not json_resp:
return res return res
@@ -1032,21 +1016,15 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
data=data, cfgid=oid) data=data, cfgid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, cfgid=oid, only_sql=True) scid=scid, cfgid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, cfgid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, cfgid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, cfgid=oid,
json_resp=False) json_resp=False)

View File

@@ -192,6 +192,8 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
{'get': 'fetch_templates'}] {'get': 'fetch_templates'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'schema']
def _init_(self, **kwargs): def _init_(self, **kwargs):
self.conn = None self.conn = None
self.template_path = None self.template_path = None
@@ -798,10 +800,8 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
:param did: database id :param did: database id
:param scid: schema id :param scid: schema id
:param dcid: FTS Dictionary id :param dcid: FTS Dictionary id
:param diff_schema: Target Schema for schema diff
:param json_resp: True then return json response :param json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
sql = render_template( sql = render_template(
@@ -847,9 +847,6 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
# Replace schema oid with schema name # Replace schema oid with schema name
res['rows'][0]['schema'] = schema res['rows'][0]['schema'] = schema
if diff_schema:
res['rows'][0]['schema'] = diff_schema
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._CREATE_SQL]), self._CREATE_SQL]),
data=res['rows'][0], data=res['rows'][0],
@@ -943,21 +940,15 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
data=data, dcid=oid) data=data, dcid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, dcid=oid, only_sql=True) scid=scid, dcid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, dcid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, dcid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, dcid=oid,
json_resp=False) json_resp=False)

View File

@@ -201,6 +201,8 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
{'get': 'headline_functions'}] {'get': 'headline_functions'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'schema']
def _init_(self, **kwargs): def _init_(self, **kwargs):
""" """
Method is used to initialize the FtsParserView and it's base view. Method is used to initialize the FtsParserView and it's base view.
@@ -848,10 +850,8 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
:param did: database id :param did: database id
:param scid: schema id :param scid: schema id
:param pid: fts tempate id :param pid: fts tempate id
:param diff_schema: Target Schema for schema diff
:param json_resp: True then return json response :param json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
try: try:
@@ -878,22 +878,6 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
) )
) )
# Used for schema diff tool
if diff_schema:
data = {'schema': scid}
# Fetch schema name from schema oid
sql = render_template("/".join([self.template_path,
self._SCHEMA_SQL]),
data=data,
conn=self.conn,
)
status, schema = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=schema)
res = res.replace(schema, diff_schema)
if not json_resp: if not json_resp:
return res return res
@@ -978,21 +962,15 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
data=data, pid=oid) data=data, pid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, pid=oid, only_sql=True) scid=scid, pid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pid=oid,
json_resp=False) json_resp=False)

View File

@@ -187,6 +187,8 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
'get_init': [{'get': 'get_init'}, {'get': 'get_init'}] 'get_init': [{'get': 'get_init'}, {'get': 'get_init'}]
}) })
keys_to_ignore = ['oid', 'oid-2', 'schema']
def _init_(self, **kwargs): def _init_(self, **kwargs):
self.conn = None self.conn = None
self.template_path = None self.template_path = None
@@ -735,10 +737,8 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
:param did: database id :param did: database id
:param scid: schema id :param scid: schema id
:param tid: fts tempate id :param tid: fts tempate id
:param diff_schema: Target Schema for schema diff
:param json_resp: True then return json response :param json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
sql = render_template( sql = render_template(
@@ -762,22 +762,6 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
"FTS Template node.") "FTS Template node.")
) )
# Used for schema diff tool
if diff_schema:
data = {'schema': scid}
# Fetch schema name from schema oid
sql = render_template("/".join([self.template_path,
self._SCHEMA_SQL]),
data=data,
conn=self.conn,
)
status, schema = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=schema)
res = res.replace(schema, diff_schema)
if not json_resp: if not json_resp:
return res return res
@@ -858,21 +842,15 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
data=data, tid=oid) data=data, tid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, tid=oid, only_sql=True) scid=scid, tid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
json_resp=False) json_resp=False)

View File

@@ -221,7 +221,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
keys_to_ignore = ['oid', 'proowner', 'typnsp', 'xmin', 'prokind', keys_to_ignore = ['oid', 'proowner', 'typnsp', 'xmin', 'prokind',
'proisagg', 'pronamespace', 'proargdefaults', 'proisagg', 'pronamespace', 'proargdefaults',
'prorettype', 'proallargtypes', 'proacl', 'oid-2'] 'prorettype', 'proallargtypes', 'proacl', 'oid-2',
'prolang']
@property @property
def required_args(self): def required_args(self):
@@ -1085,8 +1086,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
did: Database Id did: Database Id
scid: Schema Id scid: Schema Id
fnid: Function Id fnid: Function Id
json_resp:
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
resp_data = self._fetch_properties(gid, sid, did, scid, fnid) resp_data = self._fetch_properties(gid, sid, did, scid, fnid)
@@ -1131,8 +1132,6 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
status, res = self.conn.execute_2darray(sql) status, res = self.conn.execute_2darray(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
elif diff_schema:
res['rows'][0]['nspname'] = diff_schema
# Add newline and tab before each argument to format # Add newline and tab before each argument to format
name_with_default_args = self.qtIdent( name_with_default_args = self.qtIdent(
@@ -1170,9 +1169,6 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
status, res = self.conn.execute_2darray(sql) status, res = self.conn.execute_2darray(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
elif diff_schema:
res['rows'][0]['nspname'] = diff_schema
resp_data['pronamespace'] = diff_schema
# Add newline and tab before each argument to format # Add newline and tab before each argument to format
name_with_default_args = self.qtIdent( name_with_default_args = self.qtIdent(
@@ -1823,12 +1819,9 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
status, sql = self._get_sql(gid=gid, sid=sid, did=did, scid=scid, status, sql = self._get_sql(gid=gid, sid=sid, did=did, scid=scid,
data=data, fnid=oid, is_sql=False, data=data, fnid=oid, is_sql=False,
is_schema_diff=True) is_schema_diff=True)
@@ -1842,9 +1835,6 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, fnid=oid, only_sql=True) scid=scid, fnid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, fnid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, fnid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, fnid=oid,
json_resp=False) json_resp=False)

View File

@@ -12,7 +12,7 @@ import re
from functools import wraps from functools import wraps
import simplejson as json import simplejson as json
from flask import render_template, request, jsonify from flask import render_template, make_response, request, jsonify
from flask_babelex import gettext as _ from flask_babelex import gettext as _
import pgadmin.browser.server_groups.servers.databases as database import pgadmin.browser.server_groups.servers.databases as database
@@ -584,15 +584,10 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
data = kwargs.get('data') data = kwargs.get('data')
pkgid = kwargs.get('pkgid', None) pkgid = kwargs.get('pkgid', None)
sqltab = kwargs.get('sqltab', False) sqltab = kwargs.get('sqltab', False)
diff_schema = kwargs.get('diff_schema', None) is_schema_diff = kwargs.get('is_schema_diff', None)
if diff_schema:
data['schema'] = diff_schema
else:
data['schema'] = self.schema
if pkgid is not None and not sqltab: if pkgid is not None and not sqltab:
return self.get_sql_with_pkgid(scid, pkgid, data, diff_schema) return self.get_sql_with_pkgid(scid, pkgid, data, is_schema_diff)
else: else:
# To format privileges coming from client # To format privileges coming from client
if 'pkgacl' in data: if 'pkgacl' in data:
@@ -618,7 +613,15 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
data[key]['deleted'] = parse_priv_to_db( data[key]['deleted'] = parse_priv_to_db(
data[key]['deleted'], self.acl) data[key]['deleted'], self.acl)
def get_sql_with_pkgid(self, scid, pkgid, data, diff_schema): def get_sql_with_pkgid(self, scid, pkgid, data, is_schema_diff):
"""
:param scid:
:param pkgid:
:param data:
:param is_schema_diff:
:return:
"""
required_args = [ required_args = [
u'name' u'name'
] ]
@@ -666,7 +669,7 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
self._UPDATE_SQL]), self._UPDATE_SQL]),
data=data, o_data=old_data, conn=self.conn, data=data, o_data=old_data, conn=self.conn,
is_schema_diff=diff_schema) is_schema_diff=is_schema_diff)
return sql, data['name'] if 'name' in data else old_data['name'] return sql, data['name'] if 'name' in data else old_data['name']
@check_precondition(action="sql") @check_precondition(action="sql")
@@ -680,10 +683,10 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
did: Database ID did: Database ID
scid: Schema ID scid: Schema ID
pkgid: Package ID pkgid: Package ID
diff_schema: Schema diff target schema name is_schema_diff:
json_resp: json response or plain text response json_resp: json response or plain text response
""" """
diff_schema = kwargs.get('diff_schema', None) is_schema_diff = kwargs.get('is_schema_diff', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
try: try:
@@ -717,8 +720,11 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
res['rows'][0].setdefault(row['deftype'], []).append(priv) res['rows'][0].setdefault(row['deftype'], []).append(priv)
result = res['rows'][0] result = res['rows'][0]
sql, name = self.getSQL(data=result, scid=scid, pkgid=pkgid, sql, name = self.getSQL(data=result, scid=scid, pkgid=pkgid,
sqltab=True, diff_schema=diff_schema) sqltab=True,
is_schema_diff=is_schema_diff)
# Most probably this is due to error # Most probably this is due to error
if not isinstance(sql, str): if not isinstance(sql, str):
return sql return sql
@@ -841,23 +847,17 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.getSQL(data=data, scid=scid, pkgid=oid) sql, name = self.getSQL(data=data, scid=scid, pkgid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, pkgid=oid, only_sql=True) scid=scid, pkgid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pkgid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pkgid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pkgid=oid,
json_resp=False) is_schema_diff=True, json_resp=False)
return sql return sql

View File

@@ -699,10 +699,8 @@ class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
did: Database ID did: Database ID
scid: Schema ID scid: Schema ID
seid: Sequence ID seid: Sequence ID
diff_schema: Schema diff target schema name
json_resp: json response or plain text response json_resp: json response or plain text response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
sql = render_template( sql = render_template(
@@ -734,9 +732,6 @@ class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
result = res['rows'][0] result = res['rows'][0]
if diff_schema:
result['schema'] = diff_schema
result = self._formatter(result, scid, seid) result = self._formatter(result, scid, seid)
sql, name = self.get_SQL(gid, sid, did, result, scid) sql, name = self.get_SQL(gid, sid, did, result, scid)
# Most probably this is due to error # Most probably this is due to error
@@ -952,20 +947,14 @@ class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_SQL(gid, sid, did, data, scid, oid) sql, name = self.get_SQL(gid, sid, did, data, scid, oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, seid=oid, only_sql=True) scid=scid, seid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, seid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, seid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, seid=oid,
json_resp=False) json_resp=False)

View File

@@ -670,10 +670,8 @@ class SynonymView(PGChildNodeView, SchemaDiffObjectCompare):
did: Database ID did: Database ID
scid: Schema ID scid: Schema ID
syid: Synonym ID syid: Synonym ID
diff_schema:
json_resp: json_resp:
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
@@ -690,9 +688,6 @@ class SynonymView(PGChildNodeView, SchemaDiffObjectCompare):
gettext('The specified synonym could not be found.') gettext('The specified synonym could not be found.')
) )
if diff_schema:
data['schema'] = diff_schema
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
self._CREATE_SQL]), self._CREATE_SQL]),
data=data, conn=self.conn, comment=True) data=data, conn=self.conn, comment=True)
@@ -781,21 +776,14 @@ class SynonymView(PGChildNodeView, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid, sid, data, scid, oid) sql, name = self.get_sql(gid, sid, data, scid, oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, syid=oid, only_sql=True) scid=scid, syid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, syid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, syid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, syid=oid,
json_resp=False) json_resp=False)

View File

@@ -1249,8 +1249,6 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
tid = kwargs['tid'] tid = kwargs['tid']
diff_data = kwargs['diff_data'] if 'diff_data' in kwargs else None diff_data = kwargs['diff_data'] if 'diff_data' in kwargs else None
json_resp = kwargs['json_resp'] if 'json_resp' in kwargs else True json_resp = kwargs['json_resp'] if 'json_resp' in kwargs else True
diff_schema = kwargs['diff_schema'] if 'diff_schema' in kwargs else\
None
if diff_data: if diff_data:
return self._fetch_sql(did, scid, tid, diff_data, json_resp) return self._fetch_sql(did, scid, tid, diff_data, json_resp)
@@ -1273,9 +1271,6 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
if status: if status:
data = res['rows'][0] data = res['rows'][0]
if diff_schema:
data['schema'] = diff_schema
sql, partition_sql = BaseTableView.get_reverse_engineered_sql( sql, partition_sql = BaseTableView.get_reverse_engineered_sql(
self, did=did, scid=scid, tid=tid, main_sql=main_sql, self, did=did, scid=scid, tid=tid, main_sql=main_sql,
data=data, json_resp=json_resp) data=data, json_resp=json_resp)
@@ -1662,13 +1657,6 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
:param tid: Table Id :param tid: Table Id
:return: Table dataset :return: Table dataset
""" """
sub_modules = ['index', 'rule', 'trigger']
if self.manager.server_type == 'ppas' and \
self.manager.version >= 120000:
sub_modules.append('compound_trigger')
if self.manager.version >= 90500:
sub_modules.append('row_security_policy')
if tid: if tid:
status, data = self._fetch_properties(did, scid, tid) status, data = self._fetch_properties(did, scid, tid)
@@ -1704,16 +1692,15 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
# Get sub module data of a specified table for object # Get sub module data of a specified table for object
# comparison # comparison
self._get_sub_module_data_for_compare(sid, did, scid, data, self._get_sub_module_data_for_compare(sid, did, scid, data,
row, sub_modules) row)
res[row['name']] = data res[row['name']] = data
return res return res
def _get_sub_module_data_for_compare(self, sid, did, scid, data, def _get_sub_module_data_for_compare(self, sid, did, scid, data, row):
row, sub_modules):
# Get sub module data of a specified table for object # Get sub module data of a specified table for object
# comparison # comparison
for module in sub_modules: for module in self.tables_sub_modules:
module_view = SchemaDiffRegistry.get_node_view(module) module_view = SchemaDiffRegistry.get_node_view(module)
if module_view.blueprint.server_type is None or \ if module_view.blueprint.server_type is None or \
self.manager.server_type in \ self.manager.server_type in \
@@ -1723,6 +1710,76 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
oid=None) oid=None)
data[module] = sub_data data[module] = sub_data
def get_submodule_template_path(self, module_name):
"""
This function is used to get the template path based on module name.
:param module_name:
:return:
"""
template_path = None
if module_name == 'index':
template_path = self.index_template_path
elif module_name == 'trigger':
template_path = self.trigger_template_path
elif module_name == 'rule':
template_path = self.rules_template_path
elif module_name == 'compound_trigger':
template_path = self.compound_trigger_template_path
elif module_name == 'row_security_policy':
template_path = self.row_security_policies_template_path
return template_path
@BaseTableView.check_precondition
def get_table_submodules_dependencies(self, **kwargs):
"""
This function is used to get the dependencies of table and it's
submodules.
:param kwargs:
:return:
"""
tid = kwargs['tid']
table_dependencies = []
table_deps = self.get_dependencies(self.conn, tid, where=None,
show_system_objects=None,
is_schema_diff=True)
if len(table_deps) > 0:
table_dependencies.extend(table_deps)
# Fetch foreign key referenced table which is considered as
# dependency.
status, fkey_deps = fkey_utils.get_fkey_dependencies(self.conn, tid)
if not status:
return internal_server_error(errormsg=fkey_deps)
if len(fkey_deps) > 0:
table_dependencies.extend(fkey_deps)
# Iterate all the submodules of the table and fetch the dependencies.
for module in self.tables_sub_modules:
module_view = SchemaDiffRegistry.get_node_view(module)
template_path = self.get_submodule_template_path(module)
SQL = render_template("/".join([template_path,
'nodes.sql']), tid=tid)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
result = module_view.get_dependencies(
self.conn, row['oid'], where=None,
show_system_objects=None, is_schema_diff=True)
if len(result) > 0:
table_dependencies.extend(result)
# Remove the same table from the dependency list
for item in table_dependencies:
if 'oid' in item and item['oid'] == tid:
table_dependencies.remove(item)
return table_dependencies
SchemaDiffRegistry(blueprint.node_type, TableView) SchemaDiffRegistry(blueprint.node_type, TableView)
TableView.register_node_view(blueprint) TableView.register_node_view(blueprint)

View File

@@ -887,7 +887,6 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
tid = kwargs.get('tid') tid = kwargs.get('tid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
@@ -927,22 +926,17 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
data['columns'] = self._column_details(tid, columns) data['columns'] = self._column_details(tid, columns)
data = trigger_definition(data) data = trigger_definition(data)
sql = self._check_and_add_compound_trigger(tid, data)
sql = self._check_and_add_compound_trigger(tid, data,
diff_schema)
return sql return sql
def _check_and_add_compound_trigger(self, tid, data, diff_schema): def _check_and_add_compound_trigger(self, tid, data):
""" """
This get compound trigger and check for disable. This get compound trigger and check for disable.
:param tid: Table Id. :param tid: Table Id.
:param data: Data. :param data: Data.
:param diff_schema: schema diff check. :param diff_schema: schema diff check.
""" """
if diff_schema:
data['schema'] = diff_schema
sql, name = compound_trigger_utils.get_sql(self.conn, sql, name = compound_trigger_utils.get_sql(self.conn,
data, data,
tid, tid,
@@ -1007,7 +1001,6 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
tgt_params = kwargs.get('target_params') tgt_params = kwargs.get('target_params')
source = kwargs.get('source') source = kwargs.get('source')
target = kwargs.get('target') target = kwargs.get('target')
target_schema = kwargs.get('target_schema')
comp_status = kwargs.get('comp_status') comp_status = kwargs.get('comp_status')
diff = '' diff = ''
@@ -1017,8 +1010,7 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
did=src_params['did'], did=src_params['did'],
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
oid=source['oid'], oid=source['oid'])
diff_schema=target_schema)
elif comp_status == 'target_only': elif comp_status == 'target_only':
diff = self.get_sql_from_diff(gid=tgt_params['gid'], diff = self.get_sql_from_diff(gid=tgt_params['gid'],
sid=tgt_params['sid'], sid=tgt_params['sid'],

View File

@@ -15,6 +15,8 @@ from pgadmin.utils.ajax import internal_server_error
from pgadmin.utils.exception import ObjectGone, ExecuteError from pgadmin.utils.exception import ObjectGone, ExecuteError
from functools import wraps from functools import wraps
FKEY_PROPERTIES_SQL = 'properties.sql'
def get_template_path(f): def get_template_path(f):
""" """
@@ -47,7 +49,7 @@ def get_foreign_keys(conn, tid, fkid=None, template_path=None):
""" """
sql = render_template("/".join( sql = render_template("/".join(
[template_path, 'properties.sql']), tid=tid, cid=fkid) [template_path, FKEY_PROPERTIES_SQL]), tid=tid, cid=fkid)
status, result = conn.execute_dict(sql) status, result = conn.execute_dict(sql)
if not status: if not status:
@@ -286,7 +288,7 @@ def _get_properties_for_fk_const(tid, fkid, data, template_path, conn):
conn: Connection. conn: Connection.
""" """
name = data['name'] if 'name' in data else None name = data['name'] if 'name' in data else None
sql = render_template("/".join([template_path, 'properties.sql']), sql = render_template("/".join([template_path, FKEY_PROPERTIES_SQL]),
tid=tid, cid=fkid) tid=tid, cid=fkid)
status, res = conn.execute_dict(sql) status, res = conn.execute_dict(sql)
if not status: if not status:
@@ -357,3 +359,29 @@ def _checks_for_schema_diff(table, schema, data):
if 'remote_table' not in data: if 'remote_table' not in data:
data['remote_table'] = None data['remote_table'] = None
@get_template_path
def get_fkey_dependencies(conn, tid, template_path=None):
"""
This function is used to get the references table of all the foreign
keys of the given table.
:param conn:
:param tid:
:param template_path:
:return:
"""
deps = []
sql = render_template("/".join(
[template_path, FKEY_PROPERTIES_SQL]), tid=tid)
status, result = conn.execute_dict(sql)
if not status:
return status, internal_server_error(errormsg=result)
for fk in result['rows']:
ref_name = fk['refnsp'] + '.' + fk['reftab']
deps.append({'type': 'table', 'name': ref_name})
return True, deps

View File

@@ -849,7 +849,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
tid = kwargs.get('tid') tid = kwargs.get('tid')
idx = kwargs.get('idx') idx = kwargs.get('idx')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None) create_mode = kwargs.get('create_mode', None)
drop_req = kwargs.get('drop_req', False) drop_req = kwargs.get('drop_req', False)
sql = '' sql = ''
@@ -864,10 +864,9 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
sql = sql.strip('\n').strip(' ') sql = sql.strip('\n').strip(' ')
elif diff_schema: elif create_mode:
schema = diff_schema
sql = index_utils.get_reverse_engineered_sql( sql = index_utils.get_reverse_engineered_sql(
self.conn, schema=schema, self.conn, schema=self.schema,
table=self.table, did=did, tid=tid, idx=idx, table=self.table, did=did, tid=tid, idx=idx,
datlastsysoid=self.datlastsysoid, datlastsysoid=self.datlastsysoid,
template_path=None, with_header=False) template_path=None, with_header=False)
@@ -1077,7 +1076,6 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
tgt_params = kwargs.get('target_params') tgt_params = kwargs.get('target_params')
source = kwargs.get('source') source = kwargs.get('source')
target = kwargs.get('target') target = kwargs.get('target')
target_schema = kwargs.get('target_schema')
comp_status = kwargs.get('comp_status') comp_status = kwargs.get('comp_status')
diff = '' diff = ''
@@ -1087,7 +1085,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
idx=source['oid'], idx=source['oid'],
diff_schema=target_schema) create_mode=True)
elif comp_status == 'target_only': elif comp_status == 'target_only':
diff = self.delete(gid=1, sid=tgt_params['sid'], diff = self.delete(gid=1, sid=tgt_params['sid'],
did=tgt_params['did'], scid=tgt_params['scid'], did=tgt_params['did'], scid=tgt_params['scid'],
@@ -1113,7 +1111,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
idx=source['oid'], idx=source['oid'],
diff_schema=target_schema, create_mode=True,
drop_req=True) drop_req=True)
else: else:
diff = self.get_sql_from_index_diff(sid=tgt_params['sid'], diff = self.get_sql_from_index_diff(sid=tgt_params['sid'],

View File

@@ -606,7 +606,6 @@ class RowSecurityView(PGChildNodeView):
tid = kwargs.get('tid') tid = kwargs.get('tid')
oid = kwargs.get('plid') oid = kwargs.get('plid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_req = kwargs.get('drop_req', False) drop_req = kwargs.get('drop_req', False)
sql = '' sql = ''
@@ -619,11 +618,9 @@ class RowSecurityView(PGChildNodeView):
sql = sql.strip('\n').strip(' ') sql = sql.strip('\n').strip(' ')
elif diff_schema: else:
schema = diff_schema
sql = row_security_policies_utils.get_reverse_engineered_sql( sql = row_security_policies_utils.get_reverse_engineered_sql(
self.conn, schema=schema, table=self.table, scid=scid, self.conn, schema=self.schema, table=self.table, scid=scid,
plid=oid, datlastsysoid=self.datlastsysoid, with_header=False) plid=oid, datlastsysoid=self.datlastsysoid, with_header=False)
drop_sql = '' drop_sql = ''
@@ -684,7 +681,6 @@ class RowSecurityView(PGChildNodeView):
tgt_params = kwargs.get('target_params') tgt_params = kwargs.get('target_params')
source = kwargs.get('source') source = kwargs.get('source')
target = kwargs.get('target') target = kwargs.get('target')
target_schema = kwargs.get('target_schema')
comp_status = kwargs.get('comp_status') comp_status = kwargs.get('comp_status')
diff = '' diff = ''
@@ -694,8 +690,7 @@ class RowSecurityView(PGChildNodeView):
did=src_params['did'], did=src_params['did'],
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
plid=source['oid'], plid=source['oid'])
diff_schema=target_schema)
elif comp_status == 'target_only': elif comp_status == 'target_only':
diff = self.delete(gid=1, diff = self.delete(gid=1,
sid=tgt_params['sid'], sid=tgt_params['sid'],
@@ -722,8 +717,7 @@ class RowSecurityView(PGChildNodeView):
did=src_params['did'], did=src_params['did'],
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
plid=source['oid'], plid=source['oid'])
diff_schema=target_schema)
return delete_sql + diff return delete_sql + diff
diff = self.get_sql_from_diff(gid=tgt_params['gid'], diff = self.get_sql_from_diff(gid=tgt_params['gid'],

View File

@@ -531,8 +531,6 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
tid = kwargs.get('tid') tid = kwargs.get('tid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
source_schema = kwargs.get('source_schema', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if drop_sql: if drop_sql:
@@ -551,43 +549,19 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
) )
res_data = parse_rule_definition(res) res_data = parse_rule_definition(res)
sql = ''
if data: if data:
if source_schema and 'statements' in data:
# Replace the source schema with the target schema
data['statements'] = data['statements'].replace(
source_schema, diff_schema)
old_data = res_data old_data = res_data
sql = render_template( sql = render_template(
"/".join([self.template_path, self._UPDATE_SQL]), "/".join([self.template_path, self._UPDATE_SQL]),
data=data, o_data=old_data data=data, o_data=old_data
) )
else: else:
RuleView._check_schema_diff(diff_schema, res_data)
sql = render_template("/".join( sql = render_template("/".join(
[self.template_path, self._CREATE_SQL]), [self.template_path, self._CREATE_SQL]),
data=res_data, display_comments=True) data=res_data, display_comments=True)
return sql return sql
@staticmethod
def _check_schema_diff(diff_schema, res_data):
"""
Check for schema diff, if yes then replace source schema with target
schema.
diff_schema: schema diff schema
res_data: response from properties sql.
"""
if diff_schema:
if 'statements' in res_data:
# Replace the source schema with the target schema
res_data['statements'] = \
res_data['statements'].replace(
res_data['schema'], diff_schema)
res_data['schema'] = diff_schema
@check_precondition @check_precondition
def dependents(self, gid, sid, did, scid, tid, rid): def dependents(self, gid, sid, did, scid, tid, rid):
""" """
@@ -675,7 +649,6 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
tgt_params = kwargs.get('target_params') tgt_params = kwargs.get('target_params')
source = kwargs.get('source') source = kwargs.get('source')
target = kwargs.get('target') target = kwargs.get('target')
target_schema = kwargs.get('target_schema')
comp_status = kwargs.get('comp_status') comp_status = kwargs.get('comp_status')
diff = '' diff = ''
@@ -685,8 +658,7 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
did=src_params['did'], did=src_params['did'],
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
oid=source['oid'], oid=source['oid'])
diff_schema=target_schema)
elif comp_status == 'target_only': elif comp_status == 'target_only':
diff = self.get_sql_from_diff(gid=tgt_params['gid'], diff = self.get_sql_from_diff(gid=tgt_params['gid'],
sid=tgt_params['sid'], sid=tgt_params['sid'],
@@ -708,8 +680,6 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
scid=tgt_params['scid'], scid=tgt_params['scid'],
tid=tgt_params['tid'], tid=tgt_params['tid'],
oid=target['oid'], oid=target['oid'],
source_schema=source['schema'],
diff_schema=target_schema,
data=diff_dict) data=diff_dict)
return diff return diff

View File

@@ -51,12 +51,15 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
'did': kwargs.get('target_did'), 'did': kwargs.get('target_did'),
'scid': kwargs.get('target_scid')} 'scid': kwargs.get('target_scid')}
group_name = kwargs.get('group_name')
ignore_whitespaces = kwargs.get('ignore_whitespaces') ignore_whitespaces = kwargs.get('ignore_whitespaces')
status, target_schema = self.get_schema(**target_params) source_tables = {}
if not status: target_tables = {}
return internal_server_error(errormsg=target_schema)
if 'scid' in source_params and source_params['scid'] is not None:
source_tables = self.fetch_tables(**source_params) source_tables = self.fetch_tables(**source_params)
if 'scid' in target_params and target_params['scid'] is not None:
target_tables = self.fetch_tables(**target_params) target_tables = self.fetch_tables(**target_params)
# If both the dict have no items then return None. # If both the dict have no items then return None.
@@ -67,11 +70,11 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
return compare_dictionaries(view_object=self, return compare_dictionaries(view_object=self,
source_params=source_params, source_params=source_params,
target_params=target_params, target_params=target_params,
target_schema=target_schema,
source_dict=source_tables, source_dict=source_tables,
target_dict=target_tables, target_dict=target_tables,
node=self.node_type, node=self.node_type,
node_label=self.blueprint.collection_label, node_label=self.blueprint.collection_label,
group_name=group_name,
ignore_whitespaces=ignore_whitespaces, ignore_whitespaces=ignore_whitespaces,
ignore_keys=self.keys_to_ignore) ignore_keys=self.keys_to_ignore)
@@ -239,7 +242,6 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
""" """
source_params = kwargs.get('source_params') source_params = kwargs.get('source_params')
target_params = kwargs.get('target_params') target_params = kwargs.get('target_params')
target_schema = kwargs.get('target_schema')
source = kwargs.get('source') source = kwargs.get('source')
target = kwargs.get('target') target = kwargs.get('target')
diff_dict = kwargs.get('diff_dict') diff_dict = kwargs.get('diff_dict')
@@ -297,7 +299,6 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
target_params=target_params, target_params=target_params,
source=dict1[item], source=dict1[item],
target=None, target=None,
target_schema=target_schema,
comp_status='source_only' comp_status='source_only'
) )
@@ -311,7 +312,6 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
target_params=target_params, target_params=target_params,
source=None, source=None,
target=dict2[item], target=dict2[item],
target_schema=target_schema,
comp_status='target_only' comp_status='target_only'
) )
@@ -329,7 +329,6 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
target_params=target_params, target_params=target_params,
source=dict1[key], source=dict1[key],
target=dict2[key], target=dict2[key],
target_schema=target_schema,
comp_status='different', comp_status='different',
parent_source_data=source, parent_source_data=source,
parent_target_data=target parent_target_data=target

View File

@@ -805,7 +805,6 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
tid = kwargs.get('tid') tid = kwargs.get('tid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
@@ -825,8 +824,6 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
only_sql=True) only_sql=True)
else: else:
schema = self.schema schema = self.schema
if diff_schema:
schema = diff_schema
SQL = trigger_utils.get_reverse_engineered_sql( SQL = trigger_utils.get_reverse_engineered_sql(
self.conn, schema=schema, table=self.table, tid=tid, self.conn, schema=schema, table=self.table, tid=tid,
trid=oid, datlastsysoid=self.datlastsysoid, trid=oid, datlastsysoid=self.datlastsysoid,
@@ -997,7 +994,6 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
tgt_params = kwargs.get('target_params') tgt_params = kwargs.get('target_params')
source = kwargs.get('source') source = kwargs.get('source')
target = kwargs.get('target') target = kwargs.get('target')
target_schema = kwargs.get('target_schema')
comp_status = kwargs.get('comp_status') comp_status = kwargs.get('comp_status')
diff = '' diff = ''
@@ -1007,8 +1003,7 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
did=src_params['did'], did=src_params['did'],
scid=src_params['scid'], scid=src_params['scid'],
tid=src_params['tid'], tid=src_params['tid'],
oid=source['oid'], oid=source['oid'])
diff_schema=target_schema)
elif comp_status == 'target_only': elif comp_status == 'target_only':
diff = self.get_sql_from_diff(gid=tgt_params['gid'], diff = self.get_sql_from_diff(gid=tgt_params['gid'],
sid=tgt_params['sid'], sid=tgt_params['sid'],

View File

@@ -145,6 +145,13 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
# Supported ACL for columns # Supported ACL for columns
self.column_acl = ['a', 'r', 'w', 'x'] self.column_acl = ['a', 'r', 'w', 'x']
# Submodule list for schema diff
self.tables_sub_modules = ['index', 'rule', 'trigger']
if server_type == 'ppas' and ver >= 120000:
self.tables_sub_modules.append('compound_trigger')
if ver >= 90500:
self.tables_sub_modules.append('row_security_policy')
return f(*args, **kwargs) return f(*args, **kwargs)
return wrap return wrap

View File

@@ -1363,10 +1363,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
did: Database ID did: Database ID
scid: Schema ID scid: Schema ID
tid: Type ID tid: Type ID
diff_schema: Target Schema for schema diff
json_resp: True then return json response json_resp: True then return json response
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
SQL = render_template( SQL = render_template(
@@ -1386,9 +1384,6 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
# Making copy of output for future use # Making copy of output for future use
data = dict(res['rows'][0]) data = dict(res['rows'][0])
if diff_schema:
data['schema'] = diff_schema
SQL = render_template("/".join([self.template_path, self._ACL_SQL]), SQL = render_template("/".join([self.template_path, self._ACL_SQL]),
scid=scid, tid=tid) scid=scid, tid=tid)
status, acl = self.conn.execute_dict(SQL) status, acl = self.conn.execute_dict(SQL)
@@ -1518,21 +1513,15 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name = self.get_sql(gid=gid, sid=sid, scid=scid, sql, name = self.get_sql(gid=gid, sid=sid, scid=scid,
data=data, tid=oid) data=data, tid=oid)
else: else:
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, tid=oid, only_sql=True) scid=scid, tid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
json_resp=False) json_resp=False)

View File

@@ -1305,9 +1305,7 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
""" """
This function will generate sql to render into the sql panel This function will generate sql to render into the sql panel
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
display_comments = True display_comments = True
if not json_resp: if not json_resp:
@@ -1329,11 +1327,6 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
) )
result = res['rows'][0] result = res['rows'][0]
if diff_schema:
result['definition'] = result['definition'].replace(
result['schema'],
diff_schema)
result['schema'] = diff_schema
# sending result to formtter # sending result to formtter
frmtd_reslt = self.formatter(result) frmtd_reslt = self.formatter(result)
@@ -1631,12 +1624,9 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
scid = kwargs.get('scid') scid = kwargs.get('scid')
oid = kwargs.get('oid') oid = kwargs.get('oid')
data = kwargs.get('data', None) data = kwargs.get('data', None)
diff_schema = kwargs.get('diff_schema', None)
drop_sql = kwargs.get('drop_sql', False) drop_sql = kwargs.get('drop_sql', False)
if data: if data:
if diff_schema:
data['schema'] = diff_schema
sql, name_or_error = self.getSQL(gid, sid, did, data, oid) sql, name_or_error = self.getSQL(gid, sid, did, data, oid)
if sql.find('DROP VIEW') != -1: if sql.find('DROP VIEW') != -1:
sql = gettext(""" sql = gettext("""
@@ -1649,9 +1639,6 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
if drop_sql: if drop_sql:
sql = self.delete(gid=gid, sid=sid, did=did, sql = self.delete(gid=gid, sid=sid, did=did,
scid=scid, vid=oid, only_sql=True) scid=scid, vid=oid, only_sql=True)
elif diff_schema:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, vid=oid,
diff_schema=diff_schema, json_resp=False)
else: else:
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, vid=oid, sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, vid=oid,
json_resp=False) json_resp=False)
@@ -1885,7 +1872,6 @@ class MViewNode(ViewNode, VacuumSettings):
""" """
This function will generate sql to render into the sql panel This function will generate sql to render into the sql panel
""" """
diff_schema = kwargs.get('diff_schema', None)
json_resp = kwargs.get('json_resp', True) json_resp = kwargs.get('json_resp', True)
display_comments = True display_comments = True
@@ -1899,12 +1885,6 @@ class MViewNode(ViewNode, VacuumSettings):
if not status: if not status:
return result return result
if diff_schema:
result['definition'] = result['definition'].replace(
result['schema'],
diff_schema)
result['schema'] = diff_schema
# merge vacuum lists into one # merge vacuum lists into one
vacuum_table = [item for item in result['vacuum_table'] vacuum_table = [item for item in result['vacuum_table']
if if

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -70,4 +70,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace', ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension')) 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -72,4 +72,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace', ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy')) 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -72,4 +72,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace', ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy')) 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -70,4 +70,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace', ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension')) 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -72,4 +72,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace', ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy')) 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -76,4 +76,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension',
'pg_synonym', 'pg_policy')) 'pg_synonym', 'pg_policy'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN CASE WHEN tg.tgpackageoid != 0 THEN 'Tc'::text ELSE 'Tr'::text END WHEN tg.oid IS NOT NULL THEN CASE WHEN tg.tgpackageoid != 0 THEN 'Tc'::text ELSE 'Tr'::text END
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -76,4 +76,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension',
'pg_synonym', 'pg_policy')) 'pg_synonym', 'pg_policy'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -74,4 +74,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension',
'pg_synonym')) 'pg_synonym'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -1,4 +1,4 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc, SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
WHEN tg.oid IS NOT NULL THEN 'Tr'::text WHEN tg.oid IS NOT NULL THEN 'Tr'::text
WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END WHEN ty.oid IS NOT NULL THEN CASE WHEN ty.typtype = 'd' THEN 'd'::text ELSE 'Ty'::text END
@@ -76,4 +76,18 @@ refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper', 'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper',
'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension',
'pg_synonym', 'pg_policy')) 'pg_synonym', 'pg_policy'))
ORDER BY refclassid, cl.relkind UNION
SELECT DISTINCT dep.deptype, dep.refclassid, dep.refobjid, cl.relkind, ad.adbin, ad.adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN CASE WHEN cl.relkind = 'r' THEN cl.relkind || COALESCE(dep.refobjsubid::text, '') ELSE cl.relkind END
ELSE '' END AS type,
NULL AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE cl.relname END AS refname,
nsc.nspname AS nspname, '0' AS is_inherits, '0' AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
WHERE dep.objid IN (SELECT oid FROM pg_rewrite WHERE ev_class={{object_id}}) AND cl.relkind not in ('v', 'm')
ORDER BY refclassid, relkind

View File

@@ -37,7 +37,8 @@ class TestDependenciesSql(SQLTemplateTestBase):
"dependencies.sql") "dependencies.sql")
template = file_as_template(template_file) template = file_as_template(template_file)
sql = template.render( sql = template.render(
where_clause="WHERE dep.objid=%s::oid" % self.table_id) where_clause="WHERE dep.objid=%s::oid" % self.table_id,
object_id=self.table_id)
return sql return sql

View File

@@ -451,7 +451,7 @@ class PGChildNodeView(NodeView):
) )
def get_dependencies(self, conn, object_id, where=None, def get_dependencies(self, conn, object_id, where=None,
show_system_objects=None): show_system_objects=None, is_schema_diff=False):
""" """
This function is used to fetch the dependencies for the selected node. This function is used to fetch the dependencies for the selected node.
@@ -459,6 +459,8 @@ class PGChildNodeView(NodeView):
conn: Connection object conn: Connection object
object_id: Object Id of the selected node. object_id: Object Id of the selected node.
where: where clause for the sql query (optional) where: where clause for the sql query (optional)
show_system_objects: System object status
is_schema_diff: True when function gets called from schema diff.
Returns: Dictionary of dependencies for the selected node. Returns: Dictionary of dependencies for the selected node.
""" """
@@ -473,10 +475,11 @@ class PGChildNodeView(NodeView):
where_clause = where where_clause = where
query = render_template("/".join([sql_path, 'dependencies.sql']), query = render_template("/".join([sql_path, 'dependencies.sql']),
where_clause=where_clause) where_clause=where_clause,
object_id=object_id)
# fetch the dependency for the selected object # fetch the dependency for the selected object
dependencies = self.__fetch_dependency(conn, query, dependencies = self.__fetch_dependency(
show_system_objects) conn, query, show_system_objects, is_schema_diff)
# fetch role dependencies # fetch role dependencies
if where_clause.find('subid') < 0: if where_clause.find('subid') < 0:
@@ -534,13 +537,16 @@ class PGChildNodeView(NodeView):
return dependents return dependents
def __fetch_dependency(self, conn, query, show_system_objects=None): def __fetch_dependency(self, conn, query, show_system_objects=None,
is_schema_diff=False):
""" """
This function is used to fetch the dependency for the selected node. This function is used to fetch the dependency for the selected node.
Args: Args:
conn: Connection object conn: Connection object
query: sql query to fetch dependencies/dependents query: sql query to fetch dependencies/dependents
show_system_objects: System object status
is_schema_diff: True when function gets called from schema diff.
Returns: Dictionary of dependency for the selected node. Returns: Dictionary of dependency for the selected node.
""" """
@@ -597,6 +603,9 @@ class PGChildNodeView(NodeView):
type_str = row['type'] type_str = row['type']
dep_str = row['deptype'] dep_str = row['deptype']
nsp_name = row['nspname'] nsp_name = row['nspname']
object_id = None
if 'refobjid' in row:
object_id = row['refobjid']
ref_name = '' ref_name = ''
if nsp_name is not None: if nsp_name is not None:
@@ -658,12 +667,24 @@ class PGChildNodeView(NodeView):
if _ref_name is not None: if _ref_name is not None:
ref_name += _ref_name ref_name += _ref_name
# If schema diff is set to True then we don't need to calculate
# field and also no need to add icon and field in the list.
if is_schema_diff and type_name != 'schema':
dependency.append(
{
'type': type_name,
'name': ref_name,
'oid': object_id
}
)
elif not is_schema_diff:
dep_type = '' dep_type = ''
if show_system_objects is None: if show_system_objects is None:
show_system_objects = self.blueprint.show_system_objects show_system_objects = self.blueprint.show_system_objects
if dep_str[0] in dep_types: if dep_str[0] in dep_types:
# if dep_type is present in the dep_types dictionary, but it's # if dep_type is present in the dep_types dictionary,
# value is None then it requires special handling. # but it's value is None then it requires special
# handling.
if dep_types[dep_str[0]] is None: if dep_types[dep_str[0]] is None:
if dep_str[0] == 'i': if dep_str[0] == 'i':
if show_system_objects: if show_system_objects:

View File

@@ -11,6 +11,7 @@
import simplejson as json import simplejson as json
import pickle import pickle
import random import random
import copy
from flask import Response, session, url_for, request from flask import Response, session, url_for, request
from flask import render_template, current_app as app from flask import render_template, current_app as app
@@ -61,7 +62,6 @@ class SchemaDiffModule(PgAdminModule):
'schema_diff.panel', 'schema_diff.panel',
'schema_diff.servers', 'schema_diff.servers',
'schema_diff.databases', 'schema_diff.databases',
'schema_diff.schemas',
'schema_diff.compare', 'schema_diff.compare',
'schema_diff.poll', 'schema_diff.poll',
'schema_diff.ddl_compare', 'schema_diff.ddl_compare',
@@ -397,46 +397,14 @@ def databases(sid):
return make_json_response(data=res) return make_json_response(data=res)
@blueprint.route(
'/schemas/<int:sid>/<int:did>',
methods=["GET"],
endpoint="schemas"
)
@login_required
def schemas(sid, did):
"""
This function will return the list of schemas for the specified
server id and database id.
"""
res = []
try:
view = SchemaDiffRegistry.get_node_view('schema')
server = Server.query.filter_by(id=sid).first()
response = view.nodes(gid=server.servergroup_id, sid=sid, did=did)
if response.status_code == 200:
schemas = json.loads(response.data)['data']
for sch in schemas:
res.append({
"value": sch['_id'],
"label": sch['label'],
"_id": sch['_id'],
"image": sch['icon'],
})
except Exception as e:
app.logger.exception(e)
return make_json_response(data=res)
@blueprint.route( @blueprint.route(
'/compare/<int:trans_id>/<int:source_sid>/<int:source_did>/' '/compare/<int:trans_id>/<int:source_sid>/<int:source_did>/'
'<int:source_scid>/<int:target_sid>/<int:target_did>/<int:target_scid>', '<int:target_sid>/<int:target_did>',
methods=["GET"], methods=["GET"],
endpoint="compare" endpoint="compare"
) )
@login_required @login_required
def compare(trans_id, source_sid, source_did, source_scid, def compare(trans_id, source_sid, source_did, target_sid, target_did):
target_sid, target_did, target_scid):
""" """
This function will compare the two schemas. This function will compare the two schemas.
""" """
@@ -463,33 +431,88 @@ def compare(trans_id, source_sid, source_did, source_scid,
pref = Preferences.module('schema_diff') pref = Preferences.module('schema_diff')
ignore_whitespaces = pref.preference('ignore_whitespaces').get() ignore_whitespaces = pref.preference('ignore_whitespaces').get()
all_registered_nodes = SchemaDiffRegistry.get_registered_nodes() # Fetch all the schemas of source and target database
node_percent = round(100 / len(all_registered_nodes)) # Compare them and get the status.
schema_result = fetch_compare_schemas(source_sid, source_did,
target_sid, target_did)
total_schema = len(schema_result['source_only']) + len(
schema_result['target_only']) + len(
schema_result['in_both_database'])
node_percent = round(100 / (total_schema * len(
SchemaDiffRegistry.get_registered_nodes())))
total_percent = 0 total_percent = 0
for node_name, node_view in all_registered_nodes.items(): # Compare Database objects
view = SchemaDiffRegistry.get_node_view(node_name) comparison_schema_result, total_percent = \
if hasattr(view, 'compare'): compare_database_objects(
msg = gettext('Comparing {0}').\ trans_id=trans_id, session_obj=session_obj,
format(gettext(view.blueprint.collection_label)) source_sid=source_sid, source_did=source_did,
diff_model_obj.set_comparison_info(msg, total_percent) target_sid=target_sid, target_did=target_did,
# Update the message and total percentage in session object diff_model_obj=diff_model_obj, total_percent=total_percent,
update_session_diff_transaction(trans_id, session_obj, node_percent=node_percent,
diff_model_obj) ignore_whitespaces=ignore_whitespaces)
comparison_result = \
comparison_result + comparison_schema_result
res = view.compare(source_sid=source_sid, # Compare Schema objects
source_did=source_did, if 'source_only' in schema_result and \
source_scid=source_scid, len(schema_result['source_only']) > 0:
target_sid=target_sid, for item in schema_result['source_only']:
target_did=target_did, comparison_schema_result, total_percent = \
target_scid=target_scid, compare_schema_objects(
trans_id=trans_id, session_obj=session_obj,
source_sid=source_sid, source_did=source_did,
source_scid=item['scid'], target_sid=target_sid,
target_did=target_did, target_scid=None,
schema_name=item['schema_name'],
diff_model_obj=diff_model_obj,
total_percent=total_percent,
node_percent=node_percent,
ignore_whitespaces=ignore_whitespaces) ignore_whitespaces=ignore_whitespaces)
if res is not None: comparison_result = \
comparison_result = comparison_result + res comparison_result + comparison_schema_result
total_percent = total_percent + node_percent
msg = gettext("Successfully compare the specified schemas.") if 'target_only' in schema_result and \
len(schema_result['target_only']) > 0:
for item in schema_result['target_only']:
comparison_schema_result, total_percent = \
compare_schema_objects(
trans_id=trans_id, session_obj=session_obj,
source_sid=source_sid, source_did=source_did,
source_scid=None, target_sid=target_sid,
target_did=target_did, target_scid=item['scid'],
schema_name=item['schema_name'],
diff_model_obj=diff_model_obj,
total_percent=total_percent,
node_percent=node_percent,
ignore_whitespaces=ignore_whitespaces)
comparison_result = \
comparison_result + comparison_schema_result
# Compare the two schema present in both the databases
if 'in_both_database' in schema_result and \
len(schema_result['in_both_database']) > 0:
for item in schema_result['in_both_database']:
comparison_schema_result, total_percent = \
compare_schema_objects(
trans_id=trans_id, session_obj=session_obj,
source_sid=source_sid, source_did=source_did,
source_scid=item['src_scid'], target_sid=target_sid,
target_did=target_did, target_scid=item['tar_scid'],
schema_name=item['schema_name'],
diff_model_obj=diff_model_obj,
total_percent=total_percent,
node_percent=node_percent,
ignore_whitespaces=ignore_whitespaces)
comparison_result = \
comparison_result + comparison_schema_result
msg = gettext("Successfully compare the specified databases.")
total_percent = 100 total_percent = 100
diff_model_obj.set_comparison_info(msg, total_percent) diff_model_obj.set_comparison_info(msg, total_percent)
# Update the message and total percentage done in session object # Update the message and total percentage done in session object
@@ -609,3 +632,169 @@ def check_version_compatibility(sid, tid):
return False, gettext('Source and Target database server must be of ' return False, gettext('Source and Target database server must be of '
'the same major version.') 'the same major version.')
def get_schemas(sid, did):
"""
This function will return the list of schemas for the specified
server id and database id.
"""
try:
view = SchemaDiffRegistry.get_node_view('schema')
server = Server.query.filter_by(id=sid).first()
response = view.nodes(gid=server.servergroup_id, sid=sid, did=did)
schemas = json.loads(response.data)['data']
return schemas
except Exception as e:
app.logger.exception(e)
return None
def compare_database_objects(**kwargs):
"""
This function is used to compare the specified schema and their children.
:param kwargs:
:return:
"""
trans_id = kwargs.get('trans_id')
session_obj = kwargs.get('session_obj')
source_sid = kwargs.get('source_sid')
source_did = kwargs.get('source_did')
target_sid = kwargs.get('target_sid')
target_did = kwargs.get('target_did')
diff_model_obj = kwargs.get('diff_model_obj')
total_percent = kwargs.get('total_percent')
node_percent = kwargs.get('node_percent')
ignore_whitespaces = kwargs.get('ignore_whitespaces')
comparison_result = []
all_registered_nodes = SchemaDiffRegistry.get_registered_nodes(None,
'Database')
for node_name, node_view in all_registered_nodes.items():
view = SchemaDiffRegistry.get_node_view(node_name)
if hasattr(view, 'compare'):
msg = gettext('Comparing {0}'). \
format(gettext(view.blueprint.collection_label))
diff_model_obj.set_comparison_info(msg, total_percent)
# Update the message and total percentage in session object
update_session_diff_transaction(trans_id, session_obj,
diff_model_obj)
res = view.compare(source_sid=source_sid,
source_did=source_did,
target_sid=target_sid,
target_did=target_did,
group_name=gettext('Database Objects'),
ignore_whitespaces=ignore_whitespaces)
if res is not None:
comparison_result = comparison_result + res
total_percent = total_percent + node_percent
return comparison_result, total_percent
def compare_schema_objects(**kwargs):
"""
This function is used to compare the specified schema and their children.
:param kwargs:
:return:
"""
trans_id = kwargs.get('trans_id')
session_obj = kwargs.get('session_obj')
source_sid = kwargs.get('source_sid')
source_did = kwargs.get('source_did')
source_scid = kwargs.get('source_scid')
target_sid = kwargs.get('target_sid')
target_did = kwargs.get('target_did')
target_scid = kwargs.get('target_scid')
schema_name = kwargs.get('schema_name')
diff_model_obj = kwargs.get('diff_model_obj')
total_percent = kwargs.get('total_percent')
node_percent = kwargs.get('node_percent')
ignore_whitespaces = kwargs.get('ignore_whitespaces')
comparison_result = []
all_registered_nodes = SchemaDiffRegistry.get_registered_nodes()
for node_name, node_view in all_registered_nodes.items():
view = SchemaDiffRegistry.get_node_view(node_name)
if hasattr(view, 'compare'):
msg = gettext('Comparing {0} of schema \'{1}\''). \
format(gettext(view.blueprint.collection_label),
gettext(schema_name))
diff_model_obj.set_comparison_info(msg, total_percent)
# Update the message and total percentage in session object
update_session_diff_transaction(trans_id, session_obj,
diff_model_obj)
res = view.compare(source_sid=source_sid,
source_did=source_did,
source_scid=source_scid,
target_sid=target_sid,
target_did=target_did,
target_scid=target_scid,
group_name=gettext(schema_name),
ignore_whitespaces=ignore_whitespaces)
if res is not None:
comparison_result = comparison_result + res
total_percent = total_percent + node_percent
# if total_percent is more then 100 then set it to less then 100
if total_percent >= 100:
total_percent = 96
return comparison_result, total_percent
def fetch_compare_schemas(source_sid, source_did, target_sid, target_did):
"""
This function is used to fetch all the schemas of source and target
database and compare them.
:param source_sid:
:param source_did:
:param target_sid:
:param target_did:
:return:
"""
source_schemas = get_schemas(source_sid, source_did)
target_schemas = get_schemas(target_sid, target_did)
src_schema_dict = {item['label']: item['_id'] for item in source_schemas}
tar_schema_dict = {item['label']: item['_id'] for item in target_schemas}
dict1 = copy.deepcopy(src_schema_dict)
dict2 = copy.deepcopy(tar_schema_dict)
# Find the duplicate keys in both the dictionaries
dict1_keys = set(dict1.keys())
dict2_keys = set(dict2.keys())
intersect_keys = dict1_keys.intersection(dict2_keys)
# Keys that are available in source and missing in target.
source_only = []
added = dict1_keys - dict2_keys
for item in added:
source_only.append({'schema_name': item,
'scid': src_schema_dict[item]})
target_only = []
# Keys that are available in target and missing in source.
removed = dict2_keys - dict1_keys
for item in removed:
target_only.append({'schema_name': item,
'scid': tar_schema_dict[item]})
in_both_database = []
for item in intersect_keys:
in_both_database.append({'schema_name': item,
'src_scid': src_schema_dict[item],
'tar_scid': tar_schema_dict[item]})
schema_result = {'source_only': source_only, 'target_only': target_only,
'in_both_database': in_both_database}
return schema_result

View File

@@ -9,20 +9,17 @@
"""Schema diff object comparison.""" """Schema diff object comparison."""
import copy
from flask import render_template from flask import render_template
from flask_babelex import gettext from flask_babelex import gettext
from pgadmin.utils.driver import get_driver from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER from config import PG_DEFAULT_DRIVER
from pgadmin.utils.ajax import internal_server_error from pgadmin.utils.ajax import internal_server_error
from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries
from pgadmin.tools.schema_diff.model import SchemaDiffModel
class SchemaDiffObjectCompare: class SchemaDiffObjectCompare:
keys_to_ignore = ['oid', 'schema'] keys_to_ignore = ['oid', 'oid-2']
@staticmethod @staticmethod
def get_schema(sid, did, scid): def get_schema(sid, did, scid):
@@ -57,27 +54,27 @@ class SchemaDiffObjectCompare:
:param kwargs: :param kwargs:
:return: :return:
""" """
source_params = {'sid': kwargs.get('source_sid'), source_params = {'sid': kwargs.get('source_sid'),
'did': kwargs.get('source_did'), 'did': kwargs.get('source_did')}
'scid': kwargs.get('source_scid')
}
target_params = {'sid': kwargs.get('target_sid'), target_params = {'sid': kwargs.get('target_sid'),
'did': kwargs.get('target_did'), 'did': kwargs.get('target_did')}
'scid': kwargs.get('target_scid')
}
group_name = kwargs.get('group_name')
ignore_whitespaces = kwargs.get('ignore_whitespaces') ignore_whitespaces = kwargs.get('ignore_whitespaces')
status, target_schema = self.get_schema(kwargs.get('target_sid'), source = {}
kwargs.get('target_did'), target = {}
kwargs.get('target_scid')
)
if not status:
return internal_server_error(errormsg=target_schema)
if group_name == 'Database Objects':
source = self.fetch_objects_to_compare(**source_params)
target = self.fetch_objects_to_compare(**target_params)
else:
source_params['scid'] = kwargs.get('source_scid')
target_params['scid'] = kwargs.get('target_scid')
if 'scid' in source_params and source_params['scid'] is not None:
source = self.fetch_objects_to_compare(**source_params) source = self.fetch_objects_to_compare(**source_params)
if 'scid' in target_params and target_params['scid'] is not None:
target = self.fetch_objects_to_compare(**target_params) target = self.fetch_objects_to_compare(**target_params)
# If both the dict have no items then return None. # If both the dict have no items then return None.
@@ -88,11 +85,11 @@ class SchemaDiffObjectCompare:
return compare_dictionaries(view_object=self, return compare_dictionaries(view_object=self,
source_params=source_params, source_params=source_params,
target_params=target_params, target_params=target_params,
target_schema=target_schema,
source_dict=source, source_dict=source,
target_dict=target, target_dict=target,
node=self.node_type, node=self.node_type,
node_label=self.blueprint.collection_label, node_label=self.blueprint.collection_label,
group_name=group_name,
ignore_whitespaces=ignore_whitespaces, ignore_whitespaces=ignore_whitespaces,
ignore_keys=self.keys_to_ignore) ignore_keys=self.keys_to_ignore)
@@ -105,17 +102,23 @@ class SchemaDiffObjectCompare:
source_params = {'gid': 1, source_params = {'gid': 1,
'sid': kwargs.get('source_sid'), 'sid': kwargs.get('source_sid'),
'did': kwargs.get('source_did'), 'did': kwargs.get('source_did'),
'scid': kwargs.get('source_scid'),
'oid': kwargs.get('source_oid') 'oid': kwargs.get('source_oid')
} }
target_params = {'gid': 1, target_params = {'gid': 1,
'sid': kwargs.get('target_sid'), 'sid': kwargs.get('target_sid'),
'did': kwargs.get('target_did'), 'did': kwargs.get('target_did'),
'scid': kwargs.get('target_scid'),
'oid': kwargs.get('target_oid') 'oid': kwargs.get('target_oid')
} }
source_scid = kwargs.get('source_scid')
if source_scid is not None and source_scid != 0:
source_params['scid'] = source_scid
target_scid = kwargs.get('target_scid')
if target_scid is not None and target_scid != 0:
target_params['scid'] = target_scid
source = self.get_sql_from_diff(**source_params) source = self.get_sql_from_diff(**source_params)
target = self.get_sql_from_diff(**target_params) target = self.get_sql_from_diff(**target_params)

View File

@@ -16,7 +16,8 @@ from pgadmin.tools.schema_diff.model import SchemaDiffModel
count = 1 count = 1
list_keys_array = ['name', 'colname', 'argid', 'token', 'option', 'conname', list_keys_array = ['name', 'colname', 'argid', 'token', 'option', 'conname',
'member_name', 'label', 'attname'] 'member_name', 'label', 'attname', 'fdwoption',
'fsrvoption', 'umoption']
def compare_dictionaries(**kwargs): def compare_dictionaries(**kwargs):
@@ -29,7 +30,7 @@ def compare_dictionaries(**kwargs):
view_object = kwargs.get('view_object') view_object = kwargs.get('view_object')
source_params = kwargs.get('source_params') source_params = kwargs.get('source_params')
target_params = kwargs.get('target_params') target_params = kwargs.get('target_params')
target_schema = kwargs.get('target_schema') group_name = kwargs.get('group_name')
source_dict = kwargs.get('source_dict') source_dict = kwargs.get('source_dict')
target_dict = kwargs.get('target_dict') target_dict = kwargs.get('target_dict')
node = kwargs.get('node') node = kwargs.get('node')
@@ -50,6 +51,7 @@ def compare_dictionaries(**kwargs):
# Keys that are available in source and missing in target. # Keys that are available in source and missing in target.
source_only = [] source_only = []
source_dependencies = []
added = dict1_keys - dict2_keys added = dict1_keys - dict2_keys
global count global count
for item in added: for item in added:
@@ -63,18 +65,25 @@ def compare_dictionaries(**kwargs):
temp_src_params['json_resp'] = False temp_src_params['json_resp'] = False
source_ddl = \ source_ddl = \
view_object.get_sql_from_table_diff(**temp_src_params) view_object.get_sql_from_table_diff(**temp_src_params)
temp_src_params.update({
'diff_schema': target_schema
})
diff_ddl = view_object.get_sql_from_table_diff(**temp_src_params) diff_ddl = view_object.get_sql_from_table_diff(**temp_src_params)
source_dependencies = \
view_object.get_table_submodules_dependencies(
**temp_src_params)
else: else:
temp_src_params = copy.deepcopy(source_params) temp_src_params = copy.deepcopy(source_params)
temp_src_params['oid'] = source_object_id temp_src_params['oid'] = source_object_id
# Provide Foreign Data Wrapper ID
if 'fdwid' in source_dict[item]:
temp_src_params['fdwid'] = source_dict[item]['fdwid']
# Provide Foreign Server ID
if 'fsid' in source_dict[item]:
temp_src_params['fsid'] = source_dict[item]['fsid']
source_ddl = view_object.get_sql_from_diff(**temp_src_params) source_ddl = view_object.get_sql_from_diff(**temp_src_params)
temp_src_params.update({
'diff_schema': target_schema
})
diff_ddl = view_object.get_sql_from_diff(**temp_src_params) diff_ddl = view_object.get_sql_from_diff(**temp_src_params)
source_dependencies = view_object.get_dependencies(
view_object.conn, source_object_id, where=None,
show_system_objects=None, is_schema_diff=True)
source_only.append({ source_only.append({
'id': count, 'id': count,
@@ -85,7 +94,9 @@ def compare_dictionaries(**kwargs):
'status': SchemaDiffModel.COMPARISON_STATUS['source_only'], 'status': SchemaDiffModel.COMPARISON_STATUS['source_only'],
'source_ddl': source_ddl, 'source_ddl': source_ddl,
'target_ddl': '', 'target_ddl': '',
'diff_ddl': diff_ddl 'diff_ddl': diff_ddl,
'group_name': group_name,
'dependencies': source_dependencies
}) })
count += 1 count += 1
@@ -110,6 +121,13 @@ def compare_dictionaries(**kwargs):
else: else:
temp_tgt_params = copy.deepcopy(target_params) temp_tgt_params = copy.deepcopy(target_params)
temp_tgt_params['oid'] = target_object_id temp_tgt_params['oid'] = target_object_id
# Provide Foreign Data Wrapper ID
if 'fdwid' in target_dict[item]:
temp_tgt_params['fdwid'] = target_dict[item]['fdwid']
# Provide Foreign Server ID
if 'fsid' in target_dict[item]:
temp_tgt_params['fsid'] = target_dict[item]['fsid']
target_ddl = view_object.get_sql_from_diff(**temp_tgt_params) target_ddl = view_object.get_sql_from_diff(**temp_tgt_params)
temp_tgt_params.update( temp_tgt_params.update(
{'drop_sql': True}) {'drop_sql': True})
@@ -124,13 +142,16 @@ def compare_dictionaries(**kwargs):
'status': SchemaDiffModel.COMPARISON_STATUS['target_only'], 'status': SchemaDiffModel.COMPARISON_STATUS['target_only'],
'source_ddl': '', 'source_ddl': '',
'target_ddl': target_ddl, 'target_ddl': target_ddl,
'diff_ddl': diff_ddl 'diff_ddl': diff_ddl,
'group_name': group_name,
'dependencies': []
}) })
count += 1 count += 1
# Compare the values of duplicates keys. # Compare the values of duplicates keys.
identical = [] identical = []
different = [] different = []
diff_dependencies = []
for key in intersect_keys: for key in intersect_keys:
source_object_id = None source_object_id = None
target_object_id = None target_object_id = None
@@ -149,7 +170,13 @@ def compare_dictionaries(**kwargs):
'oid': source_object_id, 'oid': source_object_id,
'source_oid': source_object_id, 'source_oid': source_object_id,
'target_oid': target_object_id, 'target_oid': target_object_id,
'status': SchemaDiffModel.COMPARISON_STATUS['identical'] 'status': SchemaDiffModel.COMPARISON_STATUS['identical'],
'group_name': group_name,
'dependencies': [],
'source_scid': source_params['scid']
if 'scid' in source_params else 0,
'target_scid': target_params['scid']
if 'scid' in target_params else 0,
}) })
else: else:
if node == 'table': if node == 'table':
@@ -174,12 +201,14 @@ def compare_dictionaries(**kwargs):
source_ddl = \ source_ddl = \
view_object.get_sql_from_table_diff(**temp_src_params) view_object.get_sql_from_table_diff(**temp_src_params)
diff_dependencies = \
view_object.get_table_submodules_dependencies(
**temp_src_params)
target_ddl = \ target_ddl = \
view_object.get_sql_from_table_diff(**temp_tgt_params) view_object.get_sql_from_table_diff(**temp_tgt_params)
diff_ddl = view_object.get_sql_from_submodule_diff( diff_ddl = view_object.get_sql_from_submodule_diff(
source_params=temp_src_params, source_params=temp_src_params,
target_params=temp_tgt_params, target_params=temp_tgt_params,
target_schema=target_schema,
source=dict1[key], target=dict2[key], diff_dict=diff_dict, source=dict1[key], target=dict2[key], diff_dict=diff_dict,
ignore_whitespaces=ignore_whitespaces) ignore_whitespaces=ignore_whitespaces)
else: else:
@@ -193,7 +222,19 @@ def compare_dictionaries(**kwargs):
temp_src_params['oid'] = source_object_id temp_src_params['oid'] = source_object_id
temp_tgt_params['oid'] = target_object_id temp_tgt_params['oid'] = target_object_id
# Provide Foreign Data Wrapper ID
if 'fdwid' in source_dict[key]:
temp_src_params['fdwid'] = source_dict[key]['fdwid']
temp_tgt_params['fdwid'] = target_dict[key]['fdwid']
# Provide Foreign Server ID
if 'fsid' in source_dict[key]:
temp_src_params['fsid'] = source_dict[key]['fsid']
temp_tgt_params['fsid'] = target_dict[key]['fsid']
source_ddl = view_object.get_sql_from_diff(**temp_src_params) source_ddl = view_object.get_sql_from_diff(**temp_src_params)
diff_dependencies = view_object.get_dependencies(
view_object.conn, source_object_id, where=None,
show_system_objects=None, is_schema_diff=True)
target_ddl = view_object.get_sql_from_diff(**temp_tgt_params) target_ddl = view_object.get_sql_from_diff(**temp_tgt_params)
temp_tgt_params.update( temp_tgt_params.update(
{'data': diff_dict}) {'data': diff_dict})
@@ -210,7 +251,9 @@ def compare_dictionaries(**kwargs):
'status': SchemaDiffModel.COMPARISON_STATUS['different'], 'status': SchemaDiffModel.COMPARISON_STATUS['different'],
'source_ddl': source_ddl, 'source_ddl': source_ddl,
'target_ddl': target_ddl, 'target_ddl': target_ddl,
'diff_ddl': diff_ddl 'diff_ddl': diff_ddl,
'group_name': group_name,
'dependencies': diff_dependencies
}) })
count += 1 count += 1
@@ -498,13 +541,13 @@ def sort_list(source, target):
:return: :return:
""" """
# Check the above keys are exist in the dictionary # Check the above keys are exist in the dictionary
if len(source) > 0 and type(source[0]) == dict: if source is not None and len(source) > 0 and type(source[0]) == dict:
tmp_key = is_key_exists(list_keys_array, source[0]) tmp_key = is_key_exists(list_keys_array, source[0])
if tmp_key is not None: if tmp_key is not None:
source = sorted(source, key=lambda k: k[tmp_key]) source = sorted(source, key=lambda k: k[tmp_key])
# Check the above keys are exist in the dictionary # Check the above keys are exist in the dictionary
if len(target) > 0 and type(target[0]) == dict: if target is not None and len(target) > 0 and type(target[0]) == dict:
tmp_key = is_key_exists(list_keys_array, target[0]) tmp_key = is_key_exists(list_keys_array, target[0])
if tmp_key is not None: if tmp_key is not None:
target = sorted(target, key=lambda k: k[tmp_key]) target = sorted(target, key=lambda k: k[tmp_key])

View File

@@ -162,3 +162,7 @@
.slick-cell .ml-2 { .slick-cell .ml-2 {
margin-left: 2rem !important; margin-left: 2rem !important;
} }
.slick-cell .ml-3 {
margin-left: 3rem !important;
}

View File

@@ -105,7 +105,7 @@ let SchemaDiffSelect2Control =
controlsClassName: 'pgadmin-controls pg-el-sm-11 pg-el-12', controlsClassName: 'pgadmin-controls pg-el-sm-11 pg-el-12',
}), }),
className: function() { className: function() {
return 'pgadmin-controls pg-el-sm-4'; return 'pgadmin-controls pg-el-sm-6';
}, },
events: { events: {
'focus select': 'clearInvalid', 'focus select': 'clearInvalid',

View File

@@ -39,10 +39,8 @@ export default class SchemaDiffUI {
this.model = new Backbone.Model({ this.model = new Backbone.Model({
source_sid: undefined, source_sid: undefined,
source_did: undefined, source_did: undefined,
source_scid: undefined,
target_sid: undefined, target_sid: undefined,
target_did: undefined, target_did: undefined,
target_scid: undefined,
source_ddl: undefined, source_ddl: undefined,
target_ddl: undefined, target_ddl: undefined,
diff_ddl: undefined, diff_ddl: undefined,
@@ -109,7 +107,6 @@ export default class SchemaDiffUI {
} }
raise_error_on_fail(alert_title, xhr) { raise_error_on_fail(alert_title, xhr) {
try { try {
var err = JSON.parse(xhr.responseText); var err = JSON.parse(xhr.responseText);
@@ -147,10 +144,8 @@ export default class SchemaDiffUI {
if (url_params['source_sid'] == '' || _.isUndefined(url_params['source_sid']) || if (url_params['source_sid'] == '' || _.isUndefined(url_params['source_sid']) ||
url_params['source_did'] == '' || _.isUndefined(url_params['source_did']) || url_params['source_did'] == '' || _.isUndefined(url_params['source_did']) ||
url_params['source_scid'] == '' || _.isUndefined(url_params['source_scid']) ||
url_params['target_sid'] == '' || _.isUndefined(url_params['target_sid']) || url_params['target_sid'] == '' || _.isUndefined(url_params['target_sid']) ||
url_params['target_did'] == '' || _.isUndefined(url_params['target_did']) || url_params['target_did'] == '' || _.isUndefined(url_params['target_did'])
url_params['target_scid'] == '' || _.isUndefined(url_params['target_scid'])
) { ) {
Alertify.alert(gettext('Selection Error'), gettext('Please select source and target.')); Alertify.alert(gettext('Selection Error'), gettext('Please select source and target.'));
return false; return false;
@@ -289,18 +284,18 @@ export default class SchemaDiffUI {
// Format Schema object title with appropriate icon // Format Schema object title with appropriate icon
var formatColumnTitle = function (row, cell, value, columnDef, dataContext) { var formatColumnTitle = function (row, cell, value, columnDef, dataContext) {
let icon = 'icon-' + dataContext.type; let icon = 'icon-' + dataContext.type;
return '<i class="ml-2 wcTabIcon '+ icon +'"></i><span>' + value + '</span>'; return '<i class="ml-3 wcTabIcon '+ icon +'"></i><span>' + value + '</span>';
}; };
// Grid Columns // Grid Columns
var grid_width = (self.grid_width - 47) / 2 ; var grid_width = (self.grid_width - 47) / 2 ;
var columns = [ var columns = [
checkboxSelector.getColumnDefinition(), checkboxSelector.getColumnDefinition(),
{id: 'title', name: gettext('Schema Objects'), field: 'title', minWidth: grid_width, formatter: formatColumnTitle}, {id: 'title', name: gettext('Objects'), field: 'title', minWidth: grid_width, formatter: formatColumnTitle},
{id: 'status', name: gettext('Comparison Result'), field: 'status', minWidth: grid_width}, {id: 'status', name: gettext('Comparison Result'), field: 'status', minWidth: grid_width},
{id: 'label', name: gettext('Schema Objects'), field: 'label', width: 0, minWidth: 0, maxWidth: 0, {id: 'label', name: gettext('Objects'), field: 'label', width: 0, minWidth: 0, maxWidth: 0,
cssClass: 'really-hidden', headerCssClass: 'really-hidden'}, cssClass: 'really-hidden', headerCssClass: 'really-hidden'},
{id: 'type', name: gettext('Schema Objects'), field: 'type', width: 0, minWidth: 0, maxWidth: 0, {id: 'type', name: gettext('Objects'), field: 'type', width: 0, minWidth: 0, maxWidth: 0,
cssClass: 'really-hidden', headerCssClass: 'really-hidden'}, cssClass: 'really-hidden', headerCssClass: 'really-hidden'},
{id: 'id', name: 'id', field: 'id', width: 0, minWidth: 0, maxWidth: 0, {id: 'id', name: 'id', field: 'id', width: 0, minWidth: 0, maxWidth: 0,
cssClass: 'really-hidden', headerCssClass: 'really-hidden' }, cssClass: 'really-hidden', headerCssClass: 'really-hidden' },
@@ -316,7 +311,18 @@ export default class SchemaDiffUI {
// Grouping by Schema Object // Grouping by Schema Object
self.groupBySchemaObject = function() { self.groupBySchemaObject = function() {
self.dataView.setGrouping({ self.dataView.setGrouping([{
getter: 'group_name',
formatter: function (g) {
let icon = 'icon-schema';
if (g.rows[0].group_name == 'Database Objects'){
icon = 'icon-coll-database';
}
return '<i class="wcTabIcon '+ icon +'"></i><span>' + g.rows[0].group_name;
},
aggregateCollapsed: true,
lazyTotalsCalculation: true,
}, {
getter: 'type', getter: 'type',
formatter: function (g) { formatter: function (g) {
let icon = 'icon-coll-' + g.value; let icon = 'icon-coll-' + g.value;
@@ -330,8 +336,9 @@ export default class SchemaDiffUI {
return '<i class="wcTabIcon '+ icon +'"></i><span>' + g.rows[0].label + ' - ' + gettext('Identical') + ': <strong>' + identical + '</strong>&nbsp;&nbsp;' + gettext('Different') + ': <strong>' + different + '</strong>&nbsp;&nbsp;' + gettext('Source Only') + ': <strong>' + source_only + '</strong>&nbsp;&nbsp;' + gettext('Target Only') + ': <strong>' + target_only + '</strong></span>'; return '<i class="wcTabIcon '+ icon +'"></i><span>' + g.rows[0].label + ' - ' + gettext('Identical') + ': <strong>' + identical + '</strong>&nbsp;&nbsp;' + gettext('Different') + ': <strong>' + different + '</strong>&nbsp;&nbsp;' + gettext('Source Only') + ': <strong>' + source_only + '</strong>&nbsp;&nbsp;' + gettext('Target Only') + ': <strong>' + target_only + '</strong></span>';
}, },
aggregateCollapsed: true, aggregateCollapsed: true,
collapsed: true,
lazyTotalsCalculation: true, lazyTotalsCalculation: true,
}); }]);
}; };
var groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider({ checkboxSelect: true, var groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider({ checkboxSelect: true,
@@ -503,6 +510,8 @@ export default class SchemaDiffUI {
target_oid = data.target_oid; target_oid = data.target_oid;
url_params['trans_id'] = self.trans_id; url_params['trans_id'] = self.trans_id;
url_params['source_scid'] = data.source_scid;
url_params['target_scid'] = data.target_scid;
url_params['source_oid'] = source_oid; url_params['source_oid'] = source_oid;
url_params['target_oid'] = target_oid; url_params['target_oid'] = target_oid;
url_params['comp_status'] = data.status; url_params['comp_status'] = data.status;
@@ -607,37 +616,6 @@ export default class SchemaDiffUI {
connect: function() { connect: function() {
self.connect_database(this.model.get('source_sid'), arguments[0], arguments[1]); self.connect_database(this.model.get('source_sid'), arguments[0], arguments[1]);
}, },
}, {
name: 'source_scid',
control: SchemaDiffSelect2Control,
group: 'source',
deps: ['source_sid', 'source_did'],
url: function() {
if (this.get('source_sid') && this.get('source_did'))
return url_for('schema_diff.schemas', {'sid': this.get('source_sid'), 'did': this.get('source_did')});
return false;
},
select2: {
allowClear: true,
placeholder: gettext('Select schema...'),
},
disabled: function(m) {
let self_local = this;
if (!_.isUndefined(m.get('source_did')) && !_.isNull(m.get('source_did'))
&& m.get('source_did') !== '') {
setTimeout(function() {
if (self_local.options.length > 0) {
m.set('source_scid', self_local.options[0].value);
}
}, 10);
return false;
}
setTimeout(function() {
m.set('source_scid', undefined);
}, 10);
return true;
},
}, { }, {
name: 'target_sid', label: false, name: 'target_sid', label: false,
control: SchemaDiffSelect2Control, control: SchemaDiffSelect2Control,
@@ -698,37 +676,6 @@ export default class SchemaDiffUI {
connect: function() { connect: function() {
self.connect_database(this.model.get('target_sid'), arguments[0], arguments[1]); self.connect_database(this.model.get('target_sid'), arguments[0], arguments[1]);
}, },
}, {
name: 'target_scid',
control: SchemaDiffSelect2Control,
group: 'target',
deps: ['target_sid', 'target_did'],
url: function() {
if (this.get('target_sid') && this.get('target_did'))
return url_for('schema_diff.schemas', {'sid': this.get('target_sid'), 'did': this.get('target_did')});
return false;
},
select2: {
allowClear: true,
placeholder: gettext('Select schema...'),
},
disabled: function(m) {
let self_local = this;
if (!_.isUndefined(m.get('target_did')) && !_.isNull(m.get('target_did'))
&& m.get('target_did') !== '') {
setTimeout(function() {
if (self_local.options.length > 0) {
m.set('target_scid', self_local.options[0].value);
}
}, 10);
return false;
}
setTimeout(function() {
m.set('target_scid', undefined);
}, 10);
return true;
},
}], }],
}); });
@@ -760,7 +707,7 @@ export default class SchemaDiffUI {
footer_panel.$container.find('#schema-diff-ddl-comp').append(self.footer.render().$el); footer_panel.$container.find('#schema-diff-ddl-comp').append(self.footer.render().$el);
header_panel.$container.find('#schema-diff-grid').append(`<div class='obj_properties container-fluid'> header_panel.$container.find('#schema-diff-grid').append(`<div class='obj_properties container-fluid'>
<div class='pg-panel-message'>` + gettext('Select the server, database and schema for the source and target and click <strong>Compare</strong> to compare them.') + '</div></div>'); <div class='pg-panel-message'>` + gettext('Select the server and database for the source and target and click <strong>Compare</strong> to compare them.') + '</div></div>');
self.grid_width = $('#schema-diff-grid').width(); self.grid_width = $('#schema-diff-grid').width();
self.grid_height = this.panel_obj.height(); self.grid_height = this.panel_obj.height();

View File

@@ -23,7 +23,7 @@ from pgadmin.utils.versioned_template_loader import \
get_version_mapping_directories get_version_mapping_directories
class SchemaDiffTestCase(BaseTestGenerator): class SchemaDiffTestCase():
""" This class will test the schema diff. """ """ This class will test the schema diff. """
scenarios = [ scenarios = [
# Fetching default URL for database node. # Fetching default URL for database node.