diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/publications/__init__.py index 3d98f4388..5207b79b2 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/__init__.py @@ -21,6 +21,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \ from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare +from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry +from urllib.parse import unquote class PublicationModule(CollectionNodeModule): @@ -160,10 +162,6 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): - This function will generate sql to show it in sql pane for the selected publication node. - * dependents(gid, sid, did, pbid): - - This function get the dependents and return ajax response for the - publication node. - * dependencies(self, gid, sid, did, pbid): - This function get the dependencies and return ajax response for the publication node. @@ -281,7 +279,8 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): ) status, pname = self.conn.execute_scalar(get_name_sql) table_sql = render_template( - "/".join([self.template_path, 'get_tables.sql']), + "/".join([self.template_path, + self._GET_TABLE_FOR_PUBLICATION]), pname=pname ) @@ -412,7 +411,8 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): ) status, pname = self.conn.execute_scalar(get_name_sql) table_sql = render_template( - "/".join([self.template_path, 'get_tables.sql']), + "/".join([self.template_path, + self._GET_TABLE_FOR_PUBLICATION]), pname=pname ) @@ -444,6 +444,9 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): try: data = self._parser_data_input_from_client(data) + # unquote the table data + data = self.unquote_the_table(data) + sql, name = self.get_sql(data, pbid) # Most probably this is due to error @@ -465,6 +468,22 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): except Exception as e: return internal_server_error(errormsg=str(e)) + def unquote_the_table(self, data): + """ + This function unquote the table value + :param data: + :return: data + """ + pubtable = [] + + # Unquote the values + if 'pubtable' in data: + for table in data['pubtable']: + pubtable.append(unquote(table)) + data['pubtable'] = pubtable + + return data + @check_precondition def create(self, gid, sid, did): """ @@ -495,6 +514,9 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): try: data = self._parser_data_input_from_client(data) + # unquote the table data + data = self.unquote_the_table(data) + sql = render_template("/".join([self.template_path, self._CREATE_SQL]), data=data, conn=self.conn) @@ -525,7 +547,7 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): return internal_server_error(errormsg=str(e)) @check_precondition - def delete(self, gid, sid, did, pbid=None): + def delete(self, gid, sid, did, pbid=None, only_sql=False): """ This function will drop the publication object @@ -551,6 +573,7 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): "/".join([self.template_path, self._DELETE_SQL]), pbid=pbid, conn=self.conn ) + status, pname = self.conn.execute_scalar(sql) if not status: @@ -562,6 +585,10 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): pname=pname, cascade=cascade, conn=self.conn ) + # Used for schema diff tool + if only_sql: + return sql + status, res = self.conn.execute_scalar(sql) if not status: return internal_server_error(errormsg=res) @@ -598,6 +625,9 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): except ValueError: data[k] = v try: + # unquote the table data + data = self.unquote_the_table(data) + sql, name = self.get_sql(data, pbid) # Most probably this is due to error if not isinstance(sql, str): @@ -637,6 +667,31 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): return data + def _get_table_details_to_add_and_delete(self, old_data, data): + """ + This function returns the tables which need to add and delete + :param old_data: + :param data: + :return: + """ + drop_table_data = [] + add_table_data = [] + drop_table = False + add_table = False + + for table in old_data['pubtable']: + if 'pubtable' in data and table not in data['pubtable']: + drop_table_data.append(table) + drop_table = True + + if 'pubtable' in data: + for table in data['pubtable']: + if table not in old_data['pubtable']: + add_table_data.append(table) + add_table = True + + return drop_table, add_table, drop_table_data, add_table_data + def get_sql(self, data, pbid=None): """ This function will generate sql from model data. @@ -648,9 +703,6 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): required_args = [ 'name' ] - drop_table = False - add_table = False - if pbid is not None: sql = render_template( "/".join([self.template_path, self._PROPERTIES_SQL]), pbid=pbid @@ -664,20 +716,8 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): old_data = self._get_old_table_data(res['rows'][0]['name'], res) - drop_table_data = [] - - add_table_data = [] - - for table in old_data['pubtable']: - if 'pubtable' in data and table not in data['pubtable']: - drop_table_data.append(table) - drop_table = True - - if 'pubtable' in data: - for table in data['pubtable']: - if table not in old_data['pubtable']: - add_table_data.append(table) - add_table = True + drop_table, add_table, drop_table_data, add_table_data = \ + self._get_table_details_to_add_and_delete(old_data, data) for arg in required_args: if arg not in data: @@ -743,7 +783,7 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): """ table_sql = render_template( - "/".join([self.template_path, 'get_tables.sql']), + "/".join([self.template_path, self._GET_TABLE_FOR_PUBLICATION]), pname=pname ) @@ -854,5 +894,99 @@ class PublicationView(PGChildNodeView, SchemaDiffObjectCompare): status=200 ) + def get_dependencies(self, conn, object_id, where=None, + show_system_objects=None, is_schema_diff=False): + """ + This function gets the dependencies and returns an ajax response + for the publication node. + :param conn: + :param object_id: + :param where: + :param show_system_objects: + :param is_schema_diff: + :return: dependencies result + """ + + get_name_sql = render_template( + "/".join([self.template_path, self._DELETE_SQL]), + pbid=object_id, conn=self.conn + ) + status, pname = self.conn.execute_scalar(get_name_sql) + table_sql = render_template( + "/".join([self.template_path, 'dependencies.sql']), + pname=pname + ) + status, res = self.conn.execute_dict(table_sql) + if not status: + return internal_server_error(errormsg=res) + + dependencies_result = [] + + for pub_table in res['rows']: + dependencies_result.append( + {'type': 'table', + 'name': pub_table['pubtable'], + 'field': 'normal', + 'oid': pub_table['oid']}) + + return dependencies_result + + @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, name = self.get_sql(data=data, pbid=oid) + else: + if drop_sql: + sql = self.delete(gid=gid, sid=sid, did=did, + pbid=oid, only_sql=True) + else: + sql = self.sql(gid=gid, sid=sid, did=did, pbid=oid, + json_resp=False) + return sql + +SchemaDiffRegistry(blueprint.node_type, PublicationView, 'Database') PublicationView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/delete.sql index 98cb5d0d1..7efb13acf 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/delete.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/delete.sql @@ -1,6 +1,6 @@ {# ============= Get the publication name using oid ============= #} {% if pbid %} - SELECT pubname FROM pg_publication WHERE oid = {{pbid}}::oid; +SELECT pubname FROM pg_publication WHERE oid = {{pbid}}::oid; {% endif %} {# ============= Drop the publication ============= #} {% if pname %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/dependencies.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/dependencies.sql new file mode 100644 index 000000000..46399e304 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/dependencies.sql @@ -0,0 +1,5 @@ +SELECT cl.oid AS oid, +quote_ident(pgb_table.schemaname)||'.'||quote_ident(pgb_table.tablename) AS pubtable +FROM pg_publication_tables pgb_table +LEFT JOIN pg_class cl ON pgb_table.tablename = cl.relname +WHERE pubname = '{{ pname }}' AND pgb_table.schemaname NOT LIKE 'pgagent'; diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql index f5f702503..874cf00eb 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql @@ -1,6 +1,6 @@ SELECT quote_ident(c.table_schema)||'.'||quote_ident(c.table_name) AS table FROM information_schema.tables c -where c.table_type = 'BASE TABLE' +WHERE c.table_type = 'BASE TABLE' AND c.table_schema NOT LIKE 'pg\_%' AND c.table_schema NOT LIKE 'pgagent' AND c.table_schema NOT IN ('information_schema') ORDER BY 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_position.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_position.sql index 656f6907f..80914b606 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_position.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_position.sql @@ -1 +1 @@ -SELECT oid, pubname AS name FROM pg_publication where pubname = '{{ pubname }}'; +SELECT oid, pubname AS name FROM pg_publication WHERE pubname = '{{ pubname }}'; diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_tables.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_tables.sql index b18039b9a..1849b65ea 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_tables.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_tables.sql @@ -1 +1,3 @@ -SELECT quote_ident(pgb_table.schemaname)||'.'||quote_ident(pgb_table.tablename) AS pubtable FROM pg_publication_tables pgb_table where pubname = '{{ pname }}' and pgb_table.schemaname NOT LIKE 'pgagent'; +SELECT quote_ident(pgb_table.schemaname)||'.'||quote_ident(pgb_table.tablename) +AS pubtable FROM pg_publication_tables pgb_table WHERE pubname = '{{ pname }}' +AND pgb_table.schemaname NOT LIKE 'pgagent'; diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py index e970e79e9..fe91f1bbc 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py @@ -169,7 +169,7 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): - This function get the dependents and return ajax response for the subscription node. - * dependencies(self, gid, sid, did, subid): + * dependencies(gid, sid, did, subid): - This function get the dependencies and return ajax response for the subscription node. """ @@ -379,28 +379,10 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): return True, res['rows'][0] - @check_precondition - def dependents(self, gid, sid, did, subid): - """ - This function gets the dependents and returns an ajax response - for the view node. - - Args: - gid: Server Group ID - sid: Server ID - did: Database ID - subid: View ID - """ - dependents_result = self.get_dependents(self.conn, subid) - return ajax_response( - response=dependents_result, - status=200 - ) - @check_precondition def statistics(self, gid, sid, did, subid): """ - This function gets the dependents and returns an ajax response + This function gets the statistics and returns an ajax response for the view node. Args: @@ -418,24 +400,6 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): status=200 ) - @check_precondition - def dependencies(self, gid, sid, did, subid): - """ - This function gets the dependencies and returns an ajax response - for the view node. - - Args: - gid: Server Group ID - sid: Server ID - did: Database ID - subid: View ID - """ - dependencies_result = self.get_dependencies(self.conn, subid) - return ajax_response( - response=dependencies_result, - status=200 - ) - @check_precondition def update(self, gid, sid, did, subid): """ @@ -537,7 +501,7 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): return internal_server_error(errormsg=str(e)) @check_precondition - def delete(self, gid, sid, did, subid=None): + def delete(self, gid, sid, did, subid=None, only_sql=False): """ This function will drop the subscription object @@ -575,6 +539,10 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): subname=subname, cascade=cascade, conn=self.conn ) + # Used for schema diff tool + if only_sql: + return sql + status, res = self.conn.execute_scalar(sql) if not status: return internal_server_error(errormsg=res) @@ -625,26 +593,32 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): except Exception as e: return internal_server_error(errormsg=str(e)) - def get_details(self, data, old_data): + def get_required_details(self, data, old_data): """ This function returns the required data to create subscription :param data: - :return: + :return:data , old_data """ required_args = ['name'] required_connection_args = ['host', 'port', 'username', 'db', 'connect_timeout', 'passfile'] + + # Set connection time out to zero if initial set + # value is replaced to '' + if 'connect_timeout' in data and data['connect_timeout'] == '': + data['connect_timeout'] = 0 + for arg in required_args: - if arg not in data and arg in old_data: + if arg not in data: data[arg] = old_data[arg] for arg in required_connection_args: - if arg not in data and arg in old_data: - data[arg] = old_data[arg] + if arg in data: + old_data[arg] = data[arg] - return data + return data, old_data def get_sql(self, data, subid=None, operation=None): """ @@ -655,10 +629,6 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): subid: Subscription ID """ - required_args = ['name'] - - required_connection_args = ['host', 'port', 'username', 'db', - 'connect_timeout', 'passfile'] if operation == 'msql': dummy = True else: @@ -677,13 +647,7 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): return gone(self._NOT_FOUND_PUB_INFORMATION) old_data = res['rows'][0] - for arg in required_args: - if arg not in data: - data[arg] = old_data[arg] - - for arg in required_connection_args: - if arg in data: - old_data[arg] = data[arg] + data, old_data = self.get_required_details(data, old_data) if 'slot_name' in data and data['slot_name'] == '': data['slot_name'] = 'None' @@ -702,6 +666,11 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): return sql.strip('\n'), data['name'] def get_connection(self, connection_details): + """ + This function is used to connect to DB and returns the publications + :param connection_details: + :return: publication list + """ passfile = connection_details['passfile'] if \ 'passfile' in connection_details and \ @@ -772,13 +741,13 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): def sql(self, gid, sid, did, subid, json_resp=True): """ This function will generate sql to show in the sql pane for the - selected publication node. + selected subscription node. Args: gid: Server Group ID sid: Server ID did: Database ID - subid: Publication ID + subid: Subscription ID json_resp: """ sql = render_template( @@ -794,8 +763,11 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): # Making copy of output for future use old_data = dict(res['rows'][0]) - if old_data['slot_name'] is None and 'create_slot' not in old_data: - old_data['create_slot'] = False + old_data['create_slot'] = False + if old_data['enabled']: + old_data['connect'] = True + else: + old_data['connect'] = False sql = render_template("/".join([self.template_path, self._CREATE_SQL]), @@ -856,5 +828,111 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): status=200 ) + def get_dependencies(self, conn, object_id, where=None, + show_system_objects=None, is_schema_diff=False): + """ + This function gets the dependencies and returns an ajax response + for the subscription node. + :param conn: + :param object_id: + :param where: + :param show_system_objects: + :param is_schema_diff: + :return: dependencies result + """ + + get_name_sql = render_template( + "/".join([self.template_path, self._DELETE_SQL]), + subid=object_id, conn=self.conn + ) + status, subname = self.conn.execute_scalar(get_name_sql) + table_sql = render_template( + "/".join([self.template_path, 'dependencies.sql']), + subname=subname + ) + status, res = self.conn.execute_dict(table_sql) + if not status: + return internal_server_error(errormsg=res) + dependencies_result = [] + + for publication in res['rows'][0]['pub']: + dependencies_result.append( + {'type': 'publication', + 'name': publication, + 'field': 'normal'}) + + return dependencies_result + + @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, + did=did + ) + 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: + if 'pub' in data and type(data['pub']) == str: + # Convert publication details to list + data['pub'] = data['pub'].split(',,') + sql, name = self.get_sql(data=data, subid=oid) + else: + if drop_sql: + sql = self.delete(gid=gid, sid=sid, did=did, + subid=oid, only_sql=True) + else: + sql = self.sql(gid=gid, sid=sid, did=did, subid=oid, + json_resp=False) + if 'source' in kwargs: + sql_header = \ + '-- WARNING:\n' \ + '-- create_slot will be set to false by ' \ + 'default.' + sql_header += "\n\n" + + sql_header += sql + sql = sql_header + return sql + + +SchemaDiffRegistry(blueprint.node_type, SubscriptionView, 'Database') SubscriptionView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js index caa084827..6c1b71521 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js @@ -77,6 +77,7 @@ define('pgadmin.node.subscription', [ name: undefined, subowner: undefined, pubtable: undefined, + connect_timeout: undefined, pub:[], enabled:true, create_slot: true, diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/dependencies.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/dependencies.sql new file mode 100644 index 000000000..a71f0cd25 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/dependencies.sql @@ -0,0 +1,2 @@ +SELECT subpublications AS pub FROM pg_subscription +WHERE subname = '{{subname}}'; diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_maintenance_db.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_maintenance_db.sql index b341b0935..1a2d6204b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_maintenance_db.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_maintenance_db.sql @@ -5,4 +5,4 @@ CREATE SUBSCRIPTION test_alter_subscription CONNECTION 'host=localhost port=5432 user=postgres dbname=edb' PUBLICATION sample__1 - WITH (enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'remote_apply'); + WITH (connect = false, enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'remote_apply'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_subscription.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_subscription.sql index 8010a4959..ce72dfcab 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_subscription.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_subscription.sql @@ -5,4 +5,4 @@ CREATE SUBSCRIPTION test_alter_subscription CONNECTION 'host=localhost port=5432 user=postgres dbname=postgres' PUBLICATION sample__1 - WITH (enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'off'); + WITH (connect = false, enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'off'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_sync.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_sync.sql index 54e678273..03debd0b8 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_sync.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/alter_sync.sql @@ -5,4 +5,4 @@ CREATE SUBSCRIPTION test_alter_subscription CONNECTION 'host=localhost port=5432 user=postgres dbname=postgres' PUBLICATION sample__1 - WITH (enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'remote_apply'); + WITH (connect = false, enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'remote_apply'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/create_subscription.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/create_subscription.sql index a7819f196..6548c5f7e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/create_subscription.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/10_plus/create_subscription.sql @@ -5,4 +5,4 @@ CREATE SUBSCRIPTION test_create_subscription CONNECTION 'host=localhost port=5432 user=postgres dbname=postgres' PUBLICATION sample__1 - WITH (enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'off'); + WITH (connect = false, enabled = false, create_slot = false, slot_name = None, synchronous_commit = 'off'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/subscription_test_data.json b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/subscription_test_data.json index 4773557fe..dca2e5a78 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/subscription_test_data.json +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/subscription_test_data.json @@ -14,12 +14,12 @@ "subowner": "postgres", "enabled": false, "host": "localhost", - "slot_name": "NONE", + "slot_name": "None", "service": "", "port": 5432, "password": "", "sync": "off", - "pub": "PLACE_HOLDER" + "pub": "[\"sample__1\"]" }, "mocking_required": false, "mock_data": {}, @@ -42,12 +42,12 @@ "subowner": "postgres", "enabled": false, "host": "localhost", - "slot_name": "NONE", + "slot_name": "None", "service": "", "port": 5432, "password": "", "sync": "off", - "pub": "PLACE_HOLDER" + "pub": "[\"sample__1\"]" }, "mocking_required": false, "mock_data": {}, @@ -70,12 +70,12 @@ "subowner": "postgres", "enabled": false, "host": "localhost", - "slot_name": "NONE", + "slot_name": "None", "service": "", "port": 5432, "password": "", "sync": "off", - "pub": "PLACE_HOLDER" + "pub": "[\"sample__1\"]" }, "mocking_required": false, "mock_data": {}, @@ -98,12 +98,12 @@ "subowner": "postgres", "enabled": false, "host": "localhost", - "slot_name": "NONE", + "slot_name": "None", "service": "", "port": 5432, "password": "", "sync": "off", - "pub": "PLACE_HOLDER" + "pub": "[\"sample__1\"]" }, "mocking_required": true, "mock_data": { @@ -128,12 +128,12 @@ "subowner": "postgres", "enabled": false, "host": "localhost", - "slot_name": "NONE", + "slot_name": "None", "service": "", "port": 5432, "password": "", "sync": "off", - "pub": "PLACE_HOLDER" + "pub": "[\"sample__1\"]" }, "mocking_required": true, "mock_data": { diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/test_subscription_create.py b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/test_subscription_create.py index 6b80182dd..d558320f4 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/test_subscription_create.py +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/tests/test_subscription_create.py @@ -59,8 +59,7 @@ class SubscriptionAddTestCase(BaseTestGenerator): """This function will subscription.""" self.test_data['name'] = \ "test_subscription_add_%s" % (str(uuid.uuid4())[1:8]) - - self.test_data['pub'] = """["sample__1"]""" + self.test_data['slot_name'] = None data = self.test_data if self.is_positive_test: diff --git a/web/pgadmin/browser/server_groups/servers/templates/depends/pg/11_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/templates/depends/pg/11_plus/dependents.sql index 853847f5a..6f2e48288 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/depends/pg/11_plus/dependents.sql +++ b/web/pgadmin/browser/server_groups/servers/templates/depends/pg/11_plus/dependents.sql @@ -19,14 +19,13 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc, WHEN ftst.oid IS NOT NULL THEN 'Ft'::text WHEN ext.oid IS NOT NULL THEN 'Ex'::text WHEN pl.oid IS NOT NULL THEN 'Rs'::text - WHEN pub_rel.oid IS NOT NULL THEN 'r'::text ELSE '' END AS type, COALESCE(coc.relname, clrw.relname) AS ownertable, CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '') ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname, evt.evtname, col.collname, ftsc.cfgname, ftsd.dictname, ftsp.prsname, - ftst.tmplname, ext.extname, pl.polname, quote_ident(pubns.nspname)||'.'||quote_ident(pubcl.relname)) + ftst.tmplname, ext.extname, pl.polname) END AS refname, COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname, colns.nspname, ftscns.nspname, ftsdns.nspname, ftspns.nspname, ftstns.nspname) AS nspname, @@ -68,12 +67,9 @@ LEFT JOIN pg_ts_template ftst ON ftst.oid=dep.objid LEFT JOIN pg_namespace ftstns ON ftst.tmplnamespace=ftstns.oid LEFT JOIN pg_extension ext ON ext.oid=dep.objid LEFT JOIN pg_policy pl ON pl.oid=dep.objid -LEFT JOIN pg_publication_rel pub_rel ON pub_rel.oid = dep.objid -LEFT JOIN pg_class pubcl ON pubcl.oid = pub_rel.prrelid -LEFT JOIN pg_namespace pubns ON pubns.oid=pubcl.relnamespace {{where_clause}} AND classid IN ( SELECT oid FROM pg_class WHERE relname IN ('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_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy', 'pg_subscription', 'pg_publication_rel')) + 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy')) ORDER BY classid, cl.relkind diff --git a/web/pgadmin/browser/server_groups/servers/templates/depends/pg/12_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/templates/depends/pg/12_plus/dependents.sql index 5bac508ae..ef76c885d 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/depends/pg/12_plus/dependents.sql +++ b/web/pgadmin/browser/server_groups/servers/templates/depends/pg/12_plus/dependents.sql @@ -19,14 +19,13 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, pg_get_expr(ad.a WHEN ftst.oid IS NOT NULL THEN 'Ft'::text WHEN ext.oid IS NOT NULL THEN 'Ex'::text WHEN pl.oid IS NOT NULL THEN 'Rs'::text - WHEN pub_rel.oid IS NOT NULL THEN 'r'::text ELSE '' END AS type, COALESCE(coc.relname, clrw.relname) AS ownertable, CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '') ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname, evt.evtname, col.collname, ftsc.cfgname, ftsd.dictname, ftsp.prsname, - ftst.tmplname, ext.extname, pl.polname, quote_ident(pubns.nspname)||'.'||quote_ident(pubcl.relname)) + ftst.tmplname, ext.extname, pl.polname) END AS refname, COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname, colns.nspname, ftscns.nspname, ftsdns.nspname, ftspns.nspname, ftstns.nspname) AS nspname, @@ -68,12 +67,9 @@ LEFT JOIN pg_ts_template ftst ON ftst.oid=dep.objid LEFT JOIN pg_namespace ftstns ON ftst.tmplnamespace=ftstns.oid LEFT JOIN pg_extension ext ON ext.oid=dep.objid LEFT JOIN pg_policy pl ON pl.oid=dep.objid -LEFT JOIN pg_publication_rel pub_rel ON pub_rel.oid = dep.objid -LEFT JOIN pg_class pubcl ON pubcl.oid = pub_rel.prrelid -LEFT JOIN pg_namespace pubns ON pubns.oid=pubcl.relnamespace {{where_clause}} AND classid IN ( SELECT oid FROM pg_class WHERE relname IN ('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_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy', 'pg_subscription', 'pg_publication_rel')) + 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy')) ORDER BY classid, cl.relkind diff --git a/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/11_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/11_plus/dependents.sql index ad70e3b93..b6e368731 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/11_plus/dependents.sql +++ b/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/11_plus/dependents.sql @@ -20,14 +20,13 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc, WHEN ext.oid IS NOT NULL THEN 'Ex'::text WHEN syn.oid IS NOT NULL THEN 'Sy'::text WHEN pl.oid IS NOT NULL THEN 'Rs'::text - WHEN pub_rel.oid IS NOT NULL THEN 'r'::text ELSE '' END AS type, COALESCE(coc.relname, clrw.relname) AS ownertable, CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '') ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname, evt.evtname, col.collname, ftsc.cfgname, ftsd.dictname, ftsp.prsname, - ftst.tmplname, ext.extname, syn.synname, pl.polname, quote_ident(pubns.nspname)||'.'||quote_ident(pubcl.relname)) + ftst.tmplname, ext.extname, syn.synname, pl.polname) END AS refname, COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname, colns.nspname, ftscns.nspname, ftsdns.nspname, ftspns.nspname, ftstns.nspname, synns.nspname) AS nspname, @@ -71,12 +70,10 @@ LEFT JOIN pg_extension ext ON ext.oid=dep.objid LEFT JOIN pg_synonym syn ON syn.oid=dep.objid LEFT JOIN pg_namespace synns ON syn.synnamespace=synns.oid LEFT JOIN pg_policy pl ON pl.oid=dep.objid -LEFT JOIN pg_publication_rel pub_rel ON pub_rel.oid = dep.objid -LEFT JOIN pg_class pubcl ON pubcl.oid = pub_rel.prrelid -LEFT JOIN pg_namespace pubns ON pubns.oid=pubcl.relnamespace {{where_clause}} AND classid IN ( SELECT oid FROM pg_class WHERE relname IN ('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_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', 'pg_policy', 'pg_subscription', 'pg_publication_rel')) + 'pg_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', + 'pg_synonym', 'pg_policy')) ORDER BY classid, cl.relkind diff --git a/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/12_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/12_plus/dependents.sql index 9b1002b64..c6781827f 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/12_plus/dependents.sql +++ b/web/pgadmin/browser/server_groups/servers/templates/depends/ppas/12_plus/dependents.sql @@ -20,14 +20,13 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, pg_get_expr(ad.a WHEN ext.oid IS NOT NULL THEN 'Ex'::text WHEN syn.oid IS NOT NULL THEN 'Sy'::text WHEN pl.oid IS NOT NULL THEN 'Rs'::text - WHEN pub_rel.oid IS NOT NULL THEN 'r'::text ELSE '' END AS type, COALESCE(coc.relname, clrw.relname) AS ownertable, CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '') ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname, evt.evtname, col.collname, ftsc.cfgname, ftsd.dictname, ftsp.prsname, - ftst.tmplname, ext.extname, syn.synname, pl.polname, quote_ident(pubns.nspname)||'.'||quote_ident(pubcl.relname)) + ftst.tmplname, ext.extname, syn.synname, pl.polname) END AS refname, COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname, colns.nspname, ftscns.nspname, ftsdns.nspname, ftspns.nspname, ftstns.nspname, synns.nspname) AS nspname, @@ -71,13 +70,10 @@ LEFT JOIN pg_extension ext ON ext.oid=dep.objid LEFT JOIN pg_synonym syn ON syn.oid=dep.objid LEFT JOIN pg_namespace synns ON syn.synnamespace=synns.oid LEFT JOIN pg_policy pl ON pl.oid=dep.objid -LEFT JOIN pg_publication_rel pub_rel ON pub_rel.oid = dep.objid -LEFT JOIN pg_class pubcl ON pubcl.oid = pub_rel.prrelid -LEFT JOIN pg_namespace pubns ON pubns.oid=pubcl.relnamespace {{where_clause}} AND classid IN ( SELECT oid FROM pg_class WHERE relname IN ('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_collation', 'pg_ts_config', 'pg_ts_dict', 'pg_ts_parser', 'pg_ts_template', 'pg_extension', - 'pg_synonym', 'pg_policy', 'pg_subscription', 'pg_publication_rel')) + 'pg_synonym', 'pg_policy')) ORDER BY classid, cl.relkind diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py index 42342e320..5dd361c28 100644 --- a/web/pgadmin/browser/utils.py +++ b/web/pgadmin/browser/utils.py @@ -393,6 +393,7 @@ class PGChildNodeView(NodeView): _GET_COLUMNS_FOR_TABLE_SQL = 'get_columns_for_table.sql' _GET_SUBTYPES_SQL = 'get_subtypes.sql' _GET_EXTERNAL_FUNCTIONS_SQL = 'get_external_functions.sql' + _GET_TABLE_FOR_PUBLICATION = 'get_tables.sql' def get_children_nodes(self, manager, **kwargs): """ @@ -638,9 +639,7 @@ class PGChildNodeView(NodeView): # if type is present in the types dictionary, but it's # value is None then it requires special handling. if type_str[0] == 'r': - if len(type_str) == 1: - type_name = 'table' - elif (type_str[1].isdigit() and int(type_str[1]) > 0) or \ + if (type_str[1].isdigit() and int(type_str[1]) > 0) or \ (len(type_str) > 2 and type_str[2].isdigit() and int(type_str[2]) > 0): type_name = 'column' diff --git a/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js b/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js index d542aa072..32903aad6 100644 --- a/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js +++ b/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js @@ -20,7 +20,8 @@ export class ModelValidation { validate() { const serviceId = this.model.get('service'), - pub = this.model.get('pub'); + pub = this.model.get('pub'), + password = this.model.get('password'); if (!this.model.isNew() && 'id' in this.model.sessAttrs) { this.err['id'] = gettext('The ID cannot be changed.'); @@ -39,12 +40,16 @@ export class ModelValidation { this.checkForEmpty('db', gettext('Maintenance database must be specified.')); this.checkForEmpty('username', gettext('Username must be specified.')); this.checkForEmpty('port', gettext('Port must be specified.')); - if(!_.isUndefined(pub) && pub.length == 0){ + if(!_.isUndefined(pub) || pub.length == 0){ + if (this.model.isNew()) + this.checkForEmpty('password', gettext('Password must be specified.')); this.checkForEmpty('pub', gettext('Publication must be specified.')); } } else { this.checkForEmpty('db', gettext('Maintenance database must be specified.')); - if(!_.isUndefined(pub) && pub.length == 0){ + if(!_.isUndefined(pub) || pub.length == 0){ + if (this.model.isNew()) + this.checkForEmpty('password', gettext('Password must be specified.')); this.checkForEmpty('pub', gettext('Publication must be specified.')); } this.clearHostAddressAndDbErrors(); diff --git a/web/pgadmin/tools/schema_diff/directory_compare.py b/web/pgadmin/tools/schema_diff/directory_compare.py index 8a1f5348d..739a91f58 100644 --- a/web/pgadmin/tools/schema_diff/directory_compare.py +++ b/web/pgadmin/tools/schema_diff/directory_compare.py @@ -68,6 +68,8 @@ def _get_source_list(**kwargs): source_ddl = view_object.get_sql_from_diff(**temp_src_params) temp_src_params.update({'target_schema': target_schema}) + # To know that the changes are in source only + temp_src_params.update({'source': True}) 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,