Fixed an issue where 'ALTER VIEW' statement is missing when the user sets the default value of a column for View. Fixes #5664

This commit is contained in:
Rahul Shirsat 2020-08-10 15:27:57 +05:30 committed by Akshay Joshi
parent 4f74609ecf
commit 604937cf66
8 changed files with 82 additions and 6 deletions

View File

@ -32,6 +32,7 @@ Bug fixes
| `Issue #5490 <https://redmine.postgresql.org/issues/5490>`_ - Make the runtime configuration dialog non-modal. | `Issue #5490 <https://redmine.postgresql.org/issues/5490>`_ - Make the runtime configuration dialog non-modal.
| `Issue #5632 <https://redmine.postgresql.org/issues/5632>`_ - Ensure that the user will be able to modify the start value of the Identity column. | `Issue #5632 <https://redmine.postgresql.org/issues/5632>`_ - Ensure that the user will be able to modify the start value of the Identity column.
| `Issue #5646 <https://redmine.postgresql.org/issues/5646>`_ - Ensure that RLS Policy node should be searchable using search object. | `Issue #5646 <https://redmine.postgresql.org/issues/5646>`_ - Ensure that RLS Policy node should be searchable using search object.
| `Issue #5664 <https://redmine.postgresql.org/issues/5664>`_ - Fixed an issue where 'ALTER VIEW' statement is missing when the user sets the default value of a column for View.
| `Issue #5670 <https://redmine.postgresql.org/issues/5670>`_ - Fixed an issue where the error message does not have a close button on utility dialogs. | `Issue #5670 <https://redmine.postgresql.org/issues/5670>`_ - Fixed an issue where the error message does not have a close button on utility dialogs.
| `Issue #5689 <https://redmine.postgresql.org/issues/5689>`_ - Added the 'ORDER BY' clause for the privileges type to fix schema diff issue. | `Issue #5689 <https://redmine.postgresql.org/issues/5689>`_ - Added the 'ORDER BY' clause for the privileges type to fix schema diff issue.
| `Issue #5708 <https://redmine.postgresql.org/issues/5708>`_ - Correct TLS certificate filename in the container deployment docs. | `Issue #5708 <https://redmine.postgresql.org/issues/5708>`_ - Correct TLS certificate filename in the container deployment docs.

View File

@ -683,6 +683,10 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
gettext("Could not find the column on the server.") gettext("Could not find the column on the server.")
) )
old_data = dict(res['rows'][0]) 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: if 'seqcycle' in old_data and old_data['seqcycle'] is False:
old_data['seqcycle'] = None old_data['seqcycle'] = None
# We will add table & schema as well # We will add table & schema as well
@ -694,7 +698,8 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
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, conn=self.conn data=data, o_data=old_data, conn=self.conn,
is_view_only=is_view_only
) )
else: else:
is_error, errmsg, sql = self._get_sql_for_create(data, is_sql) is_error, errmsg, sql = self._get_sql_for_create(data, is_sql)

View File

@ -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, 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, (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,
(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.* seq.*
FROM pg_attribute att FROM pg_attribute att
JOIN pg_type ty ON ty.oid=atttypid 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_collation coll ON att.attcollation=coll.oid
LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.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_sequence seq ON cs.oid=seq.seqrelid
LEFT OUTER JOIN pg_class tab on tab.oid = att.attrelid
WHERE att.attrelid = {{tid}}::oid WHERE att.attrelid = {{tid}}::oid
{% if clid %} {% if clid %}
AND att.attnum = {{clid}}::int AND att.attnum = {{clid}}::int

View File

@ -21,7 +21,11 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %}; COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %};
{% endif %} {% endif %}
{### Alter column default value ###} {### 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 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}}; ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}};

View File

@ -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, (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,
(CASE WHEN (att.attidentity in ('a', 'd')) THEN 'i' WHEN (att.attgenerated in ('s')) THEN 'g' ELSE 'n' END) AS colconstype, (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.* seq.*
FROM pg_attribute att FROM pg_attribute att
JOIN pg_type ty ON ty.oid=atttypid 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_collation coll ON att.attcollation=coll.oid
LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.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_sequence seq ON cs.oid=seq.seqrelid
LEFT OUTER JOIN pg_class tab on tab.oid = att.attrelid
WHERE att.attrelid = {{tid}}::oid WHERE att.attrelid = {{tid}}::oid
{% if clid %} {% if clid %}
AND att.attnum = {{clid}}::int AND att.attnum = {{clid}}::int

View File

@ -14,7 +14,8 @@ SELECT att.attname as name, att.atttypid, att.attlen, att.attnum, att.attndims,
ELSE '' END AS collspcname, 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, 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, (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 FROM pg_attribute att
JOIN pg_type ty ON ty.oid=atttypid JOIN pg_type ty ON ty.oid=atttypid
LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum 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_index pi ON pi.indrelid=att.attrelid AND indisprimary
LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid 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_namespace nspc ON coll.collnamespace=nspc.oid
LEFT OUTER JOIN pg_class tab on tab.oid = att.attrelid
WHERE att.attrelid = {{tid}}::oid WHERE att.attrelid = {{tid}}::oid
{% if clid %} {% if clid %}
AND att.attnum = {{clid}}::int AND att.attnum = {{clid}}::int

View File

@ -21,7 +21,11 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %}; COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %};
{% endif %} {% endif %}
{### Alter column default value ###} {### 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 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}}; ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}};

View File

@ -9,6 +9,7 @@
"""Implements View and Materialized View Node""" """Implements View and Materialized View Node"""
import copy
import re import re
from functools import wraps from functools import wraps
@ -815,12 +816,17 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
if is_error: if is_error:
return None, errmsg return None, errmsg
self.view_schema = old_data['schema']
try: try:
sql = render_template("/".join( sql = render_template("/".join(
[self.template_path, [self.template_path,
self._SQL_PREFIX + self._UPDATE_SQL]), data=data, self._SQL_PREFIX + self._UPDATE_SQL]), data=data,
o_data=old_data, conn=self.conn) 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: except Exception as e:
current_app.logger.exception(e) current_app.logger.exception(e)
return None, internal_server_error(errormsg=str(e)) return None, internal_server_error(errormsg=str(e))
@ -1300,6 +1306,51 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
sql_data += SQL sql_data += SQL
return sql_data 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 @check_precondition
def sql(self, gid, sid, did, scid, vid, **kwargs): 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]), [self.template_path, self._SQL_PREFIX + self._GRANT_SQL]),
data=result) 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 += SQL
sql_data += self.get_rule_sql(vid, display_comments) sql_data += self.get_rule_sql(vid, display_comments)
sql_data += self.get_trigger_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_compound_trigger_sql(vid, display_comments)
sql_data += self.get_index_sql(did, 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: if not json_resp:
return sql_data return sql_data