Hi Hackers, Attached you can find 2 patches that correct the Redmine: #3308 <https://redmine.postgresql.org/issues/3308> A Patches: 0001 - In this patch we update the SQL to retrieve the is_partitioned flag from the database 0002 - Extract and refactor the icon css class retrieval. It was scattered around the code and we moved it into it's own small class
We also realize that the class was present in some places in the javascript world. What it is strange is that we only override the icon with the partition one after a successful truncation or successful reset of statistics. Why was this behavior added? Can we remove that? Thanks Victoria & Joao
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/nodes.sql index 3e877bfc..8c1e5878 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/nodes.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/nodes.sql @@ -1,6 +1,7 @@ SELECT rel.oid, rel.relname AS name, (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid) AS triggercount, - (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgenabled = 'O') AS has_enable_triggers + (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgenabled = 'O') AS has_enable_triggers, + (CASE WHEN (SELECT count(*) from pg_partition where parrelid = rel.oid) > 0 THEN true ELSE false END) AS is_partitioned FROM pg_class rel WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid AND rel.relname NOT IN (SELECT partitiontablename FROM pg_partitions) -- 2.17.0
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 d49ca20e..a4c229a1 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 @@ -303,21 +303,17 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): if len(rset['rows']) == 0: return gone(gettext("Could not find the table.")) - if 'is_partitioned' in rset['rows'][0] and \ - rset['rows'][0]['is_partitioned']: - icon = "icon-partition" - else: - icon = "icon-table" + table_information = rset['rows'][0] + icon = self.get_icon_css_class(table_information) res = self.blueprint.generate_browser_node( - rset['rows'][0]['oid'], + table_information['oid'], scid, - rset['rows'][0]['name'], + table_information['name'], icon=icon, - tigger_count=rset['rows'][0]['triggercount'], - has_enable_triggers=rset['rows'][0]['has_enable_triggers'], - is_partitioned=rset['rows'][0]['is_partitioned'] if - 'is_partitioned' in rset['rows'][0] else False + tigger_count=table_information['triggercount'], + has_enable_triggers=table_information['has_enable_triggers'], + is_partitioned=self.is_table_partitioned(table_information) ) return make_json_response( @@ -350,10 +346,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): return internal_server_error(errormsg=rset) for row in rset['rows']: - if 'is_partitioned' in row and row['is_partitioned']: - icon = "icon-partition" - else: - icon = "icon-table" + icon = self.get_icon_css_class(row) res.append( self.blueprint.generate_browser_node( @@ -363,8 +356,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): icon=icon, tigger_count=row['triggercount'], has_enable_triggers=row['has_enable_triggers'], - is_partitioned=row['is_partitioned'] if - 'is_partitioned' in row else False, + is_partitioned=self.is_table_partitioned(row), rows_cnt=0 )) @@ -968,13 +960,11 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): try: partitions_sql = '' - partitioned = False - if 'is_partitioned' in data and data['is_partitioned']: + if self.is_table_partitioned(data): data['relkind'] = 'p' # create partition scheme data['partition_scheme'] = self.get_partition_scheme(data) partitions_sql = self.get_partitions_sql(data) - partitioned = True SQL = render_template( "/".join([self.table_template_path, 'create.sql']), @@ -1021,8 +1011,8 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings): tid, scid, data['name'], - icon="icon-partition" if partitioned else "icon-table", - is_partitioned=partitioned + icon=self.get_icon_css_class(data), + is_partitioned=self.is_table_partitioned(data) ) ) except Exception as e: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/base_partition_table.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/base_partition_table.py new file mode 100644 index 00000000..fd81f6da --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/base_partition_table.py @@ -0,0 +1,23 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2018, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + + +class BasePartitionTable: + def is_table_partitioned(self, table_info): + if ( + getattr(self, 'node_type', '') == 'partition' or + ('is_partitioned' in table_info and table_info['is_partitioned']) + ): + return True + return False + + def get_icon_css_class(self, table_info): + if self.is_table_partitioned(table_info): + return 'icon-partition' + return 'icon-table' 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 df195733..b1031d8b 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 @@ -308,7 +308,7 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings): row['oid'], tid, row['name'], - icon="icon-partition", + icon=self.get_icon_css_class({}), tigger_count=row['triggercount'], has_enable_triggers=row['has_enable_triggers'], is_partitioned=row['is_partitioned'], diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_base_partition_table.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_base_partition_table.py new file mode 100644 index 00000000..38c040f0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_base_partition_table.py @@ -0,0 +1,107 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2018, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +from pgadmin.browser.server_groups.servers.databases.schemas\ + .tables.base_partition_table import BasePartitionTable +from pgadmin.utils.route import BaseTestGenerator + + +class TestBasePartitionTable(BaseTestGenerator): + scenarios = [ + ('#is_table_partitioned when table information does not ' + 'have partition information, ' + 'it returns false', + dict( + test='is_table_partitioned', + input_parameters=dict(), + expected_return=False + )), + ('#is_table_partitioned when table information ' + 'has partition information and table is partitioned, ' + 'it returns true', + dict( + test='is_table_partitioned', + input_parameters=dict( + is_partitioned=True + ), + expected_return=True + )), + ('#is_table_partitioned when table information ' + 'has partition information and table is not partitioned, ' + 'it returns false', + dict( + test='is_table_partitioned', + input_parameters=dict( + is_partitioned=False + ), + expected_return=False + )), + ('#is_table_partitioned when node_type is present ' + 'and is partition, ' + 'it returns true', + dict( + test='is_table_partitioned', + input_parameters=dict( + is_partitioned=False + ), + node_type='partition', + expected_return=True + )), + ('#is_table_partitioned when node_type is present ' + 'and is not partition ' + 'and table is not partitioned ' + 'it returns true', + dict( + test='is_table_partitioned', + input_parameters=dict( + is_partitioned=False + ), + node_type='table', + expected_return=False + )), + + + ('#get_icon_css_class when table is partitioned ' + 'it returns icon-partition class', + dict( + test='get_icon_css_class', + input_parameters=dict( + is_partitioned=True + ), + expected_return='icon-partition' + )), + ('#get_icon_css_class when table is not partitioned ' + 'it returns icon-table class', + dict( + test='get_icon_css_class', + input_parameters=dict( + is_partitioned=False + ), + expected_return='icon-table' + )) + ] + + def runTest(self): + if self.test == 'is_table_partitioned': + self.__test_is_table_partitioned() + elif self.test == 'get_icon_css_class': + self.__test_get_icon_css_class() + + def __test_is_table_partitioned(self): + subject = BasePartitionTable() + if hasattr(self, 'node_type'): + subject.node_type = self.node_type + + self.assertEqual(subject.is_table_partitioned(self.input_parameters), + self.expected_return) + + def __test_get_icon_css_class(self): + subject = BasePartitionTable() + + self.assertEqual(subject.get_icon_css_class(self.input_parameters), + self.expected_return) 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 732ff55d..b4e88840 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 @@ -14,6 +14,9 @@ from functools import wraps import simplejson as json from flask import render_template, jsonify, request from flask_babelex import gettext + +from pgadmin.browser.server_groups.servers.databases.schemas\ + .tables.base_partition_table import BasePartitionTable from pgadmin.utils.ajax import make_json_response, internal_server_error, \ make_response as ajax_response from pgadmin.browser.server_groups.servers.databases.schemas.utils \ @@ -26,7 +29,7 @@ from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER -class BaseTableView(PGChildNodeView): +class BaseTableView(PGChildNodeView, BasePartitionTable): """ This class is base class for tables and partitioned tables. @@ -2068,13 +2071,7 @@ class BaseTableView(PGChildNodeView): partitions_oid['created'] = created partitions_oid['attached'] = attached - if self.node_type == 'partition': - icon = "icon-partition" - elif 'is_partitioned' in res['rows'][0] and \ - res['rows'][0]['is_partitioned']: - icon = "icon-partition" - else: - icon = "icon-table" + icon = self.get_icon_css_class(res['rows'][0]) if 'relkind' in res['rows'][0] and \ res['rows'][0]['relkind'] == 'p': -- 2.17.0