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 aa03b02b0..955af8bc1 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 @@ -496,7 +496,7 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): "Could not find the required parameter (%s).") % arg ) try: - SQL, nameOrError = self.getSQL(gid, sid, did, scid, data) + SQL, nameOrError = self.getSQL(gid, sid, did, data) if SQL is None: return nameOrError SQL = SQL.strip('\n').strip(' ') @@ -541,7 +541,7 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): request.data, encoding='utf-8' ) try: - SQL, name = self.getSQL(gid, sid, did, scid, data, vid) + SQL, name = self.getSQL(gid, sid, did, data, vid) if SQL is None: return name SQL = SQL.strip('\n').strip(' ') @@ -678,7 +678,7 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): except ValueError: data[k] = v - sql, nameOrError = self.getSQL(gid, sid, did, scid, data, vid) + sql, nameOrError = self.getSQL(gid, sid, did, data, vid) if sql is None: return nameOrError @@ -692,7 +692,7 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): status=200 ) - def getSQL(self, gid, sid, did, scid, data, vid=None): + def getSQL(self, gid, sid, did, data, vid=None): """ This function will generate sql from model data """ @@ -716,22 +716,6 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): if 'schema' not in data: data['schema'] = res['rows'][0]['schema'] - DEL_SQL = None - if 'definition' in data: - new_def = re.sub(r"\W", "", data['definition']).split('FROM') - old_def = re.sub(r"\W", "", res['rows'][0]['definition'] - ).split('FROM') - if 'definition' in data and ( - len(old_def) > 1 or len(new_def) > 1 - ) and( - old_def[0] != new_def[0] and - old_def[0] not in new_def[0] - ): - DEL_SQL = self.delete(gid=gid, sid=sid, did=did, - scid=scid, - vid=vid, only_sql=True - ) - try: acls = render_template( "/".join([self.template_path, 'sql/allowed_privs.json']) @@ -750,14 +734,53 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): data[aclcol][key] = parse_priv_to_db( data[aclcol][key], allowedacl['acl'] ) + data['del_sql'] = False + old_data['acl_sql'] = '' + + if 'definition' in data and self.manager.server_type == 'pg': + new_def = re.sub(r"\W", "", data['definition']).split('FROM') + old_def = re.sub(r"\W", "", res['rows'][0]['definition'] + ).split('FROM') + if 'definition' in data and ( + len(old_def) > 1 or len(new_def) > 1 + ) and( + old_def[0] != new_def[0] and + old_def[0] not in new_def[0] + ): + data['del_sql'] = True + + # If we drop and recreate the view, the + # privileges must be restored + + # Fetch all privileges for view + sql_acl = render_template("/".join( + [self.template_path, 'sql/acl.sql']), vid=vid) + status, dataclres = self.conn.execute_dict(sql_acl) + if not status: + return internal_server_error(errormsg=res) + + for row in dataclres['rows']: + priv = parse_priv_from_db(row) + res['rows'][0].setdefault(row['deftype'], [] + ).append(priv) + + old_data.update(res['rows'][0]) + + # Privileges + for aclcol in acls: + if aclcol in old_data: + allowedacl = acls[aclcol] + old_data[aclcol] = parse_priv_to_db( + old_data[aclcol], allowedacl['acl']) + + old_data['acl_sql'] = render_template("/".join( + [self.template_path, 'sql/grant.sql']), data=old_data) try: SQL = render_template("/".join( [self.template_path, 'sql/update.sql']), data=data, o_data=old_data, conn=self.conn) - if DEL_SQL: - SQL = DEL_SQL + SQL except Exception as e: current_app.logger.exception(e) return None, internal_server_error(errormsg=str(e)) @@ -1457,7 +1480,7 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): if data: if diff_schema: data['schema'] = diff_schema - sql, nameOrError = self.getSQL(gid, sid, did, scid, data, oid) + sql, nameOrError = self.getSQL(gid, sid, did, data, oid) if sql.find('DROP VIEW') != -1: sql = gettext(""" -- Changing the columns in a view requires dropping and re-creating the view. @@ -1539,7 +1562,7 @@ class MViewNode(ViewNode, VacuumSettings): '9.3_plus' ) - def getSQL(self, gid, sid, did, scid, data, vid=None): + def getSQL(self, gid, sid, did, data, vid=None): """ This function will generate sql from model data """ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/view.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/view.js index ef8ac74cb..e7dacef47 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/view.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/view.js @@ -158,7 +158,7 @@ define('pgadmin.node.view', [ control: Backform.SqlCodeControl.extend({ onChange: function() { Backform.SqlCodeControl.prototype.onChange.apply(this, arguments); - if(this.model && this.model.changed) { + if(this.model && this.model.changed && this.model.node_info.server.server_type == 'pg') { if(this.model.origSessAttrs && (this.model.changed.definition != this.model.origSessAttrs.definition)) { let old_def = this.model.origSessAttrs.definition.replace(/\s/gi, '').split('FROM'), new_def = []; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/delete.sql index b1c173f98..788a0c2a6 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/delete.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/delete.sql @@ -9,5 +9,5 @@ LEFT JOIN pg_namespace nsp ON c.relnamespace = nsp.oid WHERE c.relfilenode = {{ vid }}; {% elif (name and nspname) %} -DROP VIEW {{ conn|qtIdent(nspname, name) }} {% if cascade %} CASCADE {% endif %}; +DROP VIEW {{ conn|qtIdent(nspname, name) }}{% if cascade %} CASCADE {% endif %}; {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql index 7576600c9..e328ad3cf 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql @@ -13,11 +13,10 @@ ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} ALTER VIEW {{ conn|qtIdent(o_data.schema, view_name ) }} SET SCHEMA {{ conn|qtIdent(data.schema) }}; {% endif %} -{% if data.owner and data.owner != o_data.owner %} -ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }} - OWNER TO {{ conn|qtIdent(data.owner) }}; -{% endif %} {% if def and def != o_data.definition.rstrip(';') %} +{% if data.del_sql %} +DROP VIEW {{ conn|qtIdent(view_schema, view_name) }}; +{% endif %} CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} {% if ((data.check_option and data.check_option.lower() != 'no') or data.security_barrier) %} WITH ({% if (data.check_option or o_data.check_option) %}check_option={{ data.check_option if data.check_option else o_data.check_option }}{{', ' }}{% endif %}security_barrier={{ data.security_barrier|lower if data.security_barrier is defined else o_data.security_barrier|default('false', 'true')|lower }}) @@ -36,13 +35,23 @@ ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} RESET (check_option); {% endif %} {% endif %} +{% if data.owner and data.owner != o_data.owner %} +ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} {% set old_comment = o_data.comment|default('', true) %} {% if (data.comment is defined and (data.comment != old_comment)) %} COMMENT ON VIEW {{ conn|qtIdent(view_schema, view_name) }} IS {{ data.comment|qtLiteral }}; +{% elif data.del_sql == True %} +COMMENT ON VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ old_comment|qtLiteral }}; {% endif %} {# The SQL generated below will change privileges #} +{% if o_data.acl_sql and o_data.acl_sql != '' %} +{{o_data['acl_sql']}} +{% endif %} {% if data.datacl %} {% if 'deleted' in data.datacl %} {% for priv in data.datacl.deleted %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_add_some_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_add_some_priv_msql.sql index 285bb2268..dc05c982c 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_add_some_priv_msql.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_add_some_priv_msql.sql @@ -1 +1,5 @@ +ALTER VIEW public."testview_$%{}[]()&*^!@""'`\/#" + SET (security_barrier=true); +ALTER VIEW public."testview_$%{}[]()&*^!@""'`\/#" + SET (check_option=cascaded); GRANT SELECT ON TABLE public."testview_$%{}[]()&*^!@""'`\/#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_definition_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_definition_msql.sql index aa577020e..0c13d741f 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_definition_msql.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/alter_view_definition_msql.sql @@ -1,3 +1,7 @@ +DROP VIEW public."testview_$%{}[]()&*^!@""'`\/#"; CREATE OR REPLACE VIEW public."testview_$%{}[]()&*^!@""'`\/#" AS SELECT * FROM test_view_table; +COMMENT ON VIEW public."testview_$%{}[]()&*^!@""'`\/#" + IS 'Testcomment-updated'; +GRANT ALL ON TABLE public."testview_$%{}[]()&*^!@""'`\/#" TO postgres; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/tests.json index 180dbfad8..14e121653 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/tests.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/9.4_plus/tests.json @@ -57,6 +57,18 @@ "expected_sql_file": "alter_view.sql", "expected_msql_file": "alter_view_msql.sql" }, + { + "type": "alter", + "name": "Alter View (changing code)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "definition": "SELECT * FROM test_view_table;" + }, + "expected_sql_file": "alter_view_definition.sql", + "expected_msql_file": "alter_view_definition_msql.sql" + }, { "type": "alter", "name": "Alter View (adding privileges)", @@ -64,6 +76,12 @@ "sql_endpoint": "NODE-view.sql_id", "msql_endpoint": "NODE-view.msql_id", "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", "datacl":{ "added":[ {