From f06c3578f6cbfdb3cd6a8ad40038bb0d9cc878fc Mon Sep 17 00:00:00 2001 From: Akshay Joshi Date: Mon, 10 Jul 2017 16:02:32 +0100 Subject: [PATCH] Fix drop/drop cascade for partitioned tables. Fixes #2550 --- .../databases/schemas/tables/__init__.py | 26 +----------- .../schemas/tables/partitions/__init__.py | 41 +++++++++++++++++++ .../tables/partitions/static/js/partition.js | 31 +++++++++----- .../schemas/tables/static/js/table.js | 8 ++-- .../table/sql/10_plus/properties.sql | 2 +- .../table/sql/9.1_plus/properties.sql | 2 +- .../servers/databases/schemas/tables/utils.py | 39 ++++++++++++++++++ 7 files changed, 108 insertions(+), 41 deletions(-) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py index cd61906e2..e22e54cfa 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py @@ -1009,12 +1009,6 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): scid: Schema ID tid: Table ID """ - # Below will decide if it's simple drop or drop with cascade call - if self.cmd == 'delete': - # This is a cascade operation - cascade = True - else: - cascade = False try: SQL = render_template( @@ -1037,25 +1031,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): ) ) - data = res['rows'][0] - - SQL = render_template( - "/".join([self.table_template_path, 'delete.sql']), - data=data, cascade=cascade, - conn=self.conn - ) - status, res = self.conn.execute_scalar(SQL) - if not status: - return internal_server_error(errormsg=res) - - return make_json_response( - success=1, - info=gettext("Table dropped"), - data={ - 'id': tid, - 'scid': scid - } - ) + return super(TableView, self).delete(gid, sid, did, scid, tid, res) except Exception as e: return internal_server_error(errormsg=str(e)) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py index a1c010f8b..41918164b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py @@ -179,6 +179,7 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings): {'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'list', 'post': 'create'} ], + 'delete': [{'delete': 'delete'}], 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'children': [{'get': 'children'}], 'sql': [{'get': 'sql'}], @@ -579,5 +580,45 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings): except Exception as e: return internal_server_error(errormsg=str(e)) + @BaseTableView.check_precondition + def delete(self, gid, sid, did, scid, tid, ptid): + """ + This function will delete the table object + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + """ + + try: + SQL = render_template( + "/".join([self.partition_template_path, 'properties.sql']), + did=did, scid=scid, tid=tid,ptid=ptid, + datlastsysoid=self.datlastsysoid + ) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + if not res['rows']: + return make_json_response( + success=0, + errormsg=gettext( + 'Error: Object not found.' + ), + info=gettext( + 'The specified partition could not be found.\n' + ) + ) + + return super(PartitionsView, self).delete( + gid, sid, did, scid, tid, res) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + PartitionsView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js index 63adb5ec5..a86372e5e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js @@ -1,9 +1,10 @@ define([ 'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'backform', 'alertify', + 'sources/alerts/alertify_wrapper', 'pgadmin.browser.collection', 'pgadmin.browser.table.partition.utils' ], -function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { +function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify, AlertifyWrapper) { if (!pgBrowser.Nodes['coll-partition']) { var databases = pgAdmin.Browser.Nodes['coll-partition'] = @@ -163,7 +164,8 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { dataType: "json", success: function(res) { if (res.success == 1) { - alertify.success(res.info); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.success(res.info); t.unload(i); t.setInode(i); t.deselect(i); @@ -176,7 +178,8 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { try { var err = $.parseJSON(xhr.responseText); if (err.success == 0) { - alertify.error(err.errormsg); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.error(err.errormsg); } } catch (e) {} t.unload(i); @@ -216,9 +219,10 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { dataType: "json", success: function(res) { if (res.success == 1) { - alertify.success(res.info); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.success(res.info); t.removeIcon(i); - data.icon = 'icon-table'; + data.icon = 'icon-partition'; t.addIcon(i, {icon: data.icon}); t.unload(i); t.setInode(i); @@ -233,7 +237,8 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { try { var err = $.parseJSON(xhr.responseText); if (err.success == 0) { - alertify.error(err.errormsg); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.error(err.errormsg); } } catch (e) {} t.unload(i); @@ -264,9 +269,10 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { type:'DELETE', success: function(res) { if (res.success == 1) { - alertify.success(res.info); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.success(res.info); t.removeIcon(i); - data.icon = 'icon-table'; + data.icon = 'icon-partition'; t.addIcon(i, {icon: data.icon}); t.unload(i); t.setInode(i); @@ -281,7 +287,8 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { try { var err = $.parseJSON(xhr.responseText); if (err.success == 0) { - alertify.error(err.errormsg); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.error(err.errormsg); } } catch (e) {} t.unload(i); @@ -313,7 +320,8 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { type:'PUT', success: function(res) { if (res.success == 1) { - alertify.success(res.info); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.success(res.info); var n = t.next(i); if (!n || !n.length) { n = t.prev(i); @@ -332,7 +340,8 @@ function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) { try { var err = $.parseJSON(xhr.responseText); if (err.success == 0) { - alertify.error(err.errormsg); + var alertifyWrapper = new AlertifyWrapper(); + alertifyWrapper.error(err.errormsg); } } catch (e) {} } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js index 077f4d524..faa8b7de4 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js @@ -172,6 +172,7 @@ define('pgadmin.node.table', [ return false; alertify.confirm( + gettext('Truncate Table'), S(gettext('Are you sure you want to truncate table %s?')).sprintf(d.label).value(), function (e) { if (e) { @@ -186,7 +187,7 @@ define('pgadmin.node.table', [ var alertifyWrapper = new AlertifyWrapper(); alertifyWrapper.success(res.info); t.removeIcon(i); - data.icon = 'icon-table'; + data.icon = data.is_partitioned ? 'icon-partition': 'icon-table'; t.addIcon(i, {icon: data.icon}); t.unload(i); t.setInode(i); @@ -209,7 +210,8 @@ define('pgadmin.node.table', [ } }); } - }); + }, function() {} + ); }, reset_table_stats: function(args) { var input = args || {}, @@ -235,7 +237,7 @@ define('pgadmin.node.table', [ var alertifyWrapper = new AlertifyWrapper(); alertifyWrapper.success(res.info); t.removeIcon(i); - data.icon = 'icon-table'; + data.icon = data.is_partitioned ? 'icon-partition': 'icon-table'; t.addIcon(i, {icon: data.icon}); t.unload(i); t.setInode(i); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql index 6d98b9d79..0090177fc 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql @@ -52,7 +52,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str, array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str, rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, - (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) AS typname, + CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname, (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, -- Added for pgAdmin4 (CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean THEN true ELSE false END) AS autovacuum_custom, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql index cb23dce9d..7cb27ef37 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql @@ -51,7 +51,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str, array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str, rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, - (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) AS typname, + CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname, (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, -- Added for pgAdmin4 (CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean THEN true ELSE false END) AS autovacuum_custom, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py index 7e10c65b1..555133f2d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py @@ -2084,6 +2084,45 @@ class BaseTableView(PGChildNodeView): } ) + def delete(self, gid, sid, did, scid, tid, res): + """ + This function will delete the table object + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + """ + + # Below will decide if it's simple drop or drop with cascade call + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + data = res['rows'][0] + + SQL = render_template( + "/".join([self.table_template_path, 'delete.sql']), + data=data, cascade=cascade, + conn=self.conn + ) + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info=gettext("Table dropped"), + data={ + 'id': tid, + 'scid': scid + } + ) + def get_schema_and_table_name(self, tid): """ This function will fetch the schema qualified name of the