From 604937cf6688eca6e05070eb798c54ccc754f467 Mon Sep 17 00:00:00 2001 From: Rahul Shirsat Date: Mon, 10 Aug 2020 15:27:57 +0530 Subject: [PATCH] Fixed an issue where 'ALTER VIEW' statement is missing when the user sets the default value of a column for View. Fixes #5664 --- docs/en_US/release_notes_4_25.rst | 1 + .../schemas/tables/columns/__init__.py | 7 ++- .../columns/sql/10_plus/properties.sql | 4 +- .../templates/columns/sql/10_plus/update.sql | 6 +- .../columns/sql/12_plus/properties.sql | 4 +- .../columns/sql/9.2_plus/properties.sql | 4 +- .../templates/columns/sql/9.2_plus/update.sql | 6 +- .../databases/schemas/views/__init__.py | 56 +++++++++++++++++++ 8 files changed, 82 insertions(+), 6 deletions(-) diff --git a/docs/en_US/release_notes_4_25.rst b/docs/en_US/release_notes_4_25.rst index 0878a3d49..d78006819 100644 --- a/docs/en_US/release_notes_4_25.rst +++ b/docs/en_US/release_notes_4_25.rst @@ -32,6 +32,7 @@ Bug fixes | `Issue #5490 `_ - Make the runtime configuration dialog non-modal. | `Issue #5632 `_ - Ensure that the user will be able to modify the start value of the Identity column. | `Issue #5646 `_ - Ensure that RLS Policy node should be searchable using search object. +| `Issue #5664 `_ - Fixed an issue where 'ALTER VIEW' statement is missing when the user sets the default value of a column for View. | `Issue #5670 `_ - Fixed an issue where the error message does not have a close button on utility dialogs. | `Issue #5689 `_ - Added the 'ORDER BY' clause for the privileges type to fix schema diff issue. | `Issue #5708 `_ - Correct TLS certificate filename in the container deployment docs. diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py index 17202a969..5bf26b212 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py @@ -683,6 +683,10 @@ class ColumnsView(PGChildNodeView, DataTypeReader): gettext("Could not find the column on the server.") ) old_data = dict(res['rows'][0]) + + is_view_only = True if 'is_view_only' in old_data and old_data[ + 'is_view_only'] else False + if 'seqcycle' in old_data and old_data['seqcycle'] is False: old_data['seqcycle'] = None # We will add table & schema as well @@ -694,7 +698,8 @@ class ColumnsView(PGChildNodeView, DataTypeReader): sql = render_template( "/".join([self.template_path, self._UPDATE_SQL]), - data=data, o_data=old_data, conn=self.conn + data=data, o_data=old_data, conn=self.conn, + is_view_only=is_view_only ) else: is_error, errmsg, sql = self._get_sql_for_create(data, is_sql) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/properties.sql index 5052f1284..a2e44c231 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/properties.sql @@ -16,7 +16,8 @@ SELECT att.attname as name, att.atttypid, att.attlen, att.attnum, att.attndims, EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk, (SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS seclabels, (CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column, - (CASE WHEN (att.attidentity in ('a', 'd')) THEN 'i' ELSE 'n' END) AS colconstype, + (CASE WHEN (att.attidentity in ('a', 'd')) THEN 'i' ELSE 'n' END) AS colconstype, tab.relname as relname, + (CASE WHEN tab.relkind = 'v' THEN true ELSE false END) AS is_view_only, seq.* FROM pg_attribute att JOIN pg_type ty ON ty.oid=atttypid @@ -27,6 +28,7 @@ FROM pg_attribute att LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid LEFT OUTER JOIN pg_sequence seq ON cs.oid=seq.seqrelid + LEFT OUTER JOIN pg_class tab on tab.oid = att.attrelid WHERE att.attrelid = {{tid}}::oid {% if clid %} AND att.attnum = {{clid}}::int diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql index cc9aa4640..3914a1c57 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql @@ -21,7 +21,11 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}} COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %}; {% endif %} {### Alter column default value ###} -{% if data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %} +{% if is_view_only and data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %} +ALTER VIEW {{conn|qtIdent(data.schema, data.table)}} + ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}}; + +{% elif data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %} ALTER TABLE {{conn|qtIdent(data.schema, data.table)}} ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/properties.sql index 0ff53130f..b42f6f66c 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/properties.sql @@ -17,7 +17,8 @@ SELECT att.attname as name, att.atttypid, att.attlen, att.attnum, att.attndims, (SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS seclabels, (CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column, (CASE WHEN (att.attidentity in ('a', 'd')) THEN 'i' WHEN (att.attgenerated in ('s')) THEN 'g' ELSE 'n' END) AS colconstype, - (CASE WHEN (att.attgenerated in ('s')) THEN pg_catalog.pg_get_expr(def.adbin, def.adrelid) END) AS genexpr, + (CASE WHEN (att.attgenerated in ('s')) THEN pg_catalog.pg_get_expr(def.adbin, def.adrelid) END) AS genexpr, tab.relname as relname, + (CASE WHEN tab.relkind = 'v' THEN true ELSE false END) AS is_view_only, seq.* FROM pg_attribute att JOIN pg_type ty ON ty.oid=atttypid @@ -28,6 +29,7 @@ FROM pg_attribute att LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid LEFT OUTER JOIN pg_sequence seq ON cs.oid=seq.seqrelid + LEFT OUTER JOIN pg_class tab on tab.oid = att.attrelid WHERE att.attrelid = {{tid}}::oid {% if clid %} AND att.attnum = {{clid}}::int diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/properties.sql index a920ebe52..7eee42940 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/properties.sql @@ -14,7 +14,8 @@ SELECT att.attname as name, att.atttypid, att.attlen, att.attnum, att.attndims, ELSE '' END AS collspcname, EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk, (SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS seclabels, - (CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column + (CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column, tab.relname as relname, + (CASE WHEN tab.relkind = 'v' THEN true ELSE false END) AS is_view_only FROM pg_attribute att JOIN pg_type ty ON ty.oid=atttypid LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum @@ -23,6 +24,7 @@ FROM pg_attribute att LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid + LEFT OUTER JOIN pg_class tab on tab.oid = att.attrelid WHERE att.attrelid = {{tid}}::oid {% if clid %} AND att.attnum = {{clid}}::int diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql index 1d9f79a19..d39f8b6b9 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql @@ -21,7 +21,11 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}} COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %}; {% endif %} {### Alter column default value ###} -{% if data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %} +{% if is_view_only and data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %} +ALTER VIEW {{conn|qtIdent(data.schema, data.table)}} + ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}}; + +{% elif data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %} ALTER TABLE {{conn|qtIdent(data.schema, data.table)}} ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py index c2d014b7e..5bd4508b5 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py @@ -9,6 +9,7 @@ """Implements View and Materialized View Node""" +import copy import re from functools import wraps @@ -815,12 +816,17 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): if is_error: return None, errmsg + self.view_schema = old_data['schema'] + try: sql = render_template("/".join( [self.template_path, self._SQL_PREFIX + self._UPDATE_SQL]), data=data, o_data=old_data, conn=self.conn) + if 'definition' in data and data['definition']: + sql += self.get_columns_sql(did, vid) + except Exception as e: current_app.logger.exception(e) return None, internal_server_error(errormsg=str(e)) @@ -1300,6 +1306,51 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): sql_data += SQL return sql_data + def get_columns_sql(self, did, vid): + """ + Get all column associated with view node, + generate their sql and render + into sql tab + """ + + sql_data = '' + SQL = render_template("/".join( + [self.column_template_path, + self._PROPERTIES_SQL.format(self.manager.version)]), + did=did, + tid=vid) + status, data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=data) + + for rows in data['rows']: + + res = { + 'name': rows['name'], + 'atttypid': rows['atttypid'], + 'attlen': rows['attlen'], + 'typnspname': rows['typnspname'], + 'defval': None, + 'table': rows['relname'], + 'schema': self.view_schema + } + + o_data = copy.deepcopy(rows) + + # Generate alter statement for default value + if 'defval' in rows and rows['defval'] is not None: + res['defval'] = rows['defval'] + o_data['defval'] = None + else: + continue + + SQL = render_template("/".join( + [self.column_template_path, + self._UPDATE_SQL.format(self.manager.version)]), + o_data=o_data, data=res, is_view_only=True) + sql_data += SQL + return sql_data + @check_precondition def sql(self, gid, sid, did, scid, vid, **kwargs): """ @@ -1376,11 +1427,16 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): [self.template_path, self._SQL_PREFIX + self._GRANT_SQL]), data=result) + if ('seclabels' in result and len(result['seclabels']) > 0)\ + or ('datacl' in result and len(result['datacl']) > 0): + SQL += "\n" + sql_data += SQL sql_data += self.get_rule_sql(vid, display_comments) sql_data += self.get_trigger_sql(vid, display_comments) sql_data += self.get_compound_trigger_sql(vid, display_comments) sql_data += self.get_index_sql(did, vid, display_comments) + sql_data += self.get_columns_sql(did, vid) if not json_resp: return sql_data