From ecde42cbed4f8238c3bbfe945e26da9f6eefdb79 Mon Sep 17 00:00:00 2001 From: Surinder Kumar Date: Fri, 20 May 2016 17:43:30 +0530 Subject: [PATCH] Implementation of View & Materialized View --- .../databases/schemas/views/__init__.py | 1471 +++++++++++++++++ .../schemas/views/children/__init__.py | 12 + .../schemas/views/static/img/coll-mview.png | Bin 0 -> 374 bytes .../schemas/views/static/img/coll-view.png | Bin 0 -> 418 bytes .../schemas/views/static/img/mview.png | Bin 0 -> 344 bytes .../schemas/views/static/img/view.png | Bin 0 -> 437 bytes .../views/templates/mview/css/mview.css | 12 + .../schemas/views/templates/mview/js/mview.js | 313 ++++ .../templates/mview/pg/9.3_plus/sql/acl.sql | 41 + .../mview/pg/9.3_plus/sql/create.sql | 41 + .../mview/pg/9.3_plus/sql/delete.sql | 13 + .../mview/pg/9.3_plus/sql/get_schema.sql | 7 + .../mview/pg/9.3_plus/sql/get_view_name.sql | 11 + .../templates/mview/pg/9.3_plus/sql/grant.sql | 6 + .../mview/pg/9.3_plus/sql/properties.sql | 111 ++ .../mview/pg/9.3_plus/sql/refresh.sql | 4 + .../mview/pg/9.3_plus/sql/update.sql | 216 +++ .../mview/pg/9.3_plus/sql/view_id.sql | 4 + .../templates/mview/ppas/9.3_plus/sql/acl.sql | 41 + .../mview/ppas/9.3_plus/sql/create.sql | 47 + .../mview/ppas/9.3_plus/sql/delete.sql | 13 + .../mview/ppas/9.3_plus/sql/get_schema.sql | 7 + .../mview/ppas/9.3_plus/sql/get_view_name.sql | 11 + .../mview/ppas/9.3_plus/sql/grant.sql | 6 + .../mview/ppas/9.3_plus/sql/properties.sql | 111 ++ .../mview/ppas/9.3_plus/sql/refresh.sql | 4 + .../mview/ppas/9.3_plus/sql/update.sql | 179 ++ .../mview/ppas/9.3_plus/sql/view_id.sql | 4 + .../schemas/views/templates/view/css/view.css | 12 + .../schemas/views/templates/view/js/view.js | 267 +++ .../templates/view/pg/9.1_plus/sql/acl.sql | 51 + .../templates/view/pg/9.1_plus/sql/create.sql | 20 + .../templates/view/pg/9.1_plus/sql/delete.sql | 13 + .../view/pg/9.1_plus/sql/get_schema.sql | 7 + .../templates/view/pg/9.1_plus/sql/grant.sql | 6 + .../view/pg/9.1_plus/sql/properties.sql | 69 + .../templates/view/pg/9.1_plus/sql/update.sql | 67 + .../view/pg/9.1_plus/sql/view_id.sql | 4 + .../templates/view/pg/9.2_plus/sql/acl.sql | 52 + .../templates/view/pg/9.2_plus/sql/create.sql | 24 + .../templates/view/pg/9.2_plus/sql/delete.sql | 13 + .../view/pg/9.2_plus/sql/get_schema.sql | 7 + .../templates/view/pg/9.2_plus/sql/grant.sql | 6 + .../view/pg/9.2_plus/sql/properties.sql | 71 + .../templates/view/pg/9.2_plus/sql/update.sql | 75 + .../view/pg/9.2_plus/sql/view_id.sql | 4 + .../templates/view/pg/9.3_plus/sql/acl.sql | 38 + .../templates/view/pg/9.3_plus/sql/create.sql | 23 + .../templates/view/pg/9.3_plus/sql/delete.sql | 13 + .../view/pg/9.3_plus/sql/get_schema.sql | 7 + .../templates/view/pg/9.3_plus/sql/grant.sql | 6 + .../view/pg/9.3_plus/sql/properties.sql | 74 + .../templates/view/pg/9.3_plus/sql/update.sql | 75 + .../view/pg/9.3_plus/sql/view_id.sql | 4 + .../templates/view/pg/9.4_plus/sql/acl.sql | 39 + .../templates/view/pg/9.4_plus/sql/create.sql | 22 + .../templates/view/pg/9.4_plus/sql/delete.sql | 13 + .../view/pg/9.4_plus/sql/get_schema.sql | 7 + .../templates/view/pg/9.4_plus/sql/grant.sql | 6 + .../view/pg/9.4_plus/sql/properties.sql | 77 + .../templates/view/pg/9.4_plus/sql/update.sql | 81 + .../view/pg/9.4_plus/sql/view_id.sql | 4 + .../templates/view/ppas/9.1_plus/sql/acl.sql | 39 + .../view/ppas/9.1_plus/sql/create.sql | 20 + .../view/ppas/9.1_plus/sql/delete.sql | 13 + .../view/ppas/9.1_plus/sql/get_schema.sql | 7 + .../view/ppas/9.1_plus/sql/grant.sql | 6 + .../view/ppas/9.1_plus/sql/properties.sql | 76 + .../view/ppas/9.1_plus/sql/update.sql | 75 + .../view/ppas/9.1_plus/sql/view_id.sql | 4 + .../templates/view/ppas/9.2_plus/sql/acl.sql | 52 + .../view/ppas/9.2_plus/sql/create.sql | 23 + .../view/ppas/9.2_plus/sql/delete.sql | 13 + .../view/ppas/9.2_plus/sql/get_schema.sql | 7 + .../view/ppas/9.2_plus/sql/grant.sql | 6 + .../view/ppas/9.2_plus/sql/properties.sql | 70 + .../view/ppas/9.2_plus/sql/update.sql | 75 + .../view/ppas/9.2_plus/sql/view_id.sql | 4 + .../templates/view/ppas/9.3_plus/sql/acl.sql | 38 + .../view/ppas/9.3_plus/sql/create.sql | 23 + .../view/ppas/9.3_plus/sql/delete.sql | 13 + .../view/ppas/9.3_plus/sql/get_schema.sql | 7 + .../view/ppas/9.3_plus/sql/grant.sql | 6 + .../view/ppas/9.3_plus/sql/properties.sql | 74 + .../view/ppas/9.3_plus/sql/update.sql | 75 + .../view/ppas/9.3_plus/sql/view_id.sql | 4 + .../templates/view/ppas/9.4_plus/sql/acl.sql | 39 + .../view/ppas/9.4_plus/sql/create.sql | 22 + .../view/ppas/9.4_plus/sql/delete.sql | 13 + .../view/ppas/9.4_plus/sql/get_schema.sql | 7 + .../view/ppas/9.4_plus/sql/grant.sql | 6 + .../view/ppas/9.4_plus/sql/properties.sql | 77 + .../view/ppas/9.4_plus/sql/update.sql | 81 + .../view/ppas/9.4_plus/sql/view_id.sql | 4 + web/pgadmin/static/js/backform.pgadmin.js | 29 +- 95 files changed, 4941 insertions(+), 9 deletions(-) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/children/__init__.py create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/img/coll-mview.png create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/img/coll-view.png create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/img/mview.png create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/img/view.png create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/css/mview.css create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/js/mview.js create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_view_name.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/refresh.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_view_name.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/refresh.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/css/view.css create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/js/view.js create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/view_id.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/acl.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/get_schema.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/grant.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/view_id.sql 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 new file mode 100644 index 000000000..fbaad8d79 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py @@ -0,0 +1,1471 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements View and Materialized View Node""" + +import simplejson as json +from flask import render_template, request, jsonify +from flask.ext.babel import gettext +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error, \ + bad_request +from pgadmin.browser.utils import PGChildNodeView +import pgadmin.browser.server_groups.servers.databases as databases +from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ + SchemaChildModule, parse_rule_definition, VacuumSettings +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +from functools import wraps + + +""" + This module is responsible for generating two nodes + 1) View + 2) Materialized View + + We have created single file because view & material view has same + functionality. It allows us to share the same submodules for both + view, and material view modules. + + This modules uses separate template paths for each respective node + - templates/view for View node + - templates/materialized_view for MaterializedView node + + [Each path contains node specific js files as well as sql template files.] +""" + + +class ViewModule(SchemaChildModule): + """ + class ViewModule(SchemaChildModule): + + A module class for View node derived from SchemaChildModule. + + Methods: + ------- + * __init__(*args, **kwargs) + - Method is used to initialize the View and it's base module. + + * get_nodes(gid, sid, did, scid) + - Method is used to generate the browser collection node. + + * node_inode() + - Method is overridden from its base class to make the node as leaf node. + + * script_load() + - Load the module script for View, when any of the server node is + initialized. + """ + NODE_TYPE = 'view' + COLLECTION_LABEL = gettext("Views") + + def __init__(self, *args, **kwargs): + """ + Method is used to initialize the ViewModule and it's base module. + + Args: + *args: + **kwargs: + """ + super(ViewModule, self).__init__(*args, **kwargs) + self.min_ver = None + self.max_ver = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate the collection node + """ + yield self.generate_browser_collection_node(scid) + + @property + def script_load(self): + """ + Load the module script for views, when any database node is + initialized, The reason is views are also listed under catalogs + which are loaded under database node. + """ + return databases.DatabaseModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css to include in the page + """ + snippets = [ + render_template( + "browser/css/collection.css", + node_type=self.node_type, + _=gettext + ), + render_template( + "view/css/view.css", + node_type=self.node_type, + _=gettext + ), + render_template( + "mview/css/mview.css", + node_type='mview', + _=gettext + ) + ] + + for submodule in self.submodules: + snippets.extend(submodule.csssnippets) + + return snippets + + +class MaterializedViewModule(ViewModule): + """ + class MaterializedViewModule(ViewModule) + A module class for the materialized view and view node derived + from ViewModule. + """ + + NODE_TYPE = 'mview' + COLLECTION_LABEL = gettext("Materialized Views") + + def __init__(self, *args, **kwargs): + """ + Method is used to initialize the MaterializedViewModule and + it's base module. + + Args: + *args: + **kwargs: + """ + super(MaterializedViewModule, self).__init__(*args, **kwargs) + self.min_ver = 90300 + self.max_ver = None + +view_blueprint = ViewModule(__name__) +mview_blueprint = MaterializedViewModule( + __name__) + + +def check_precondition(f): + """ + This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to instance of the method. + + Assumptions: + This function will always be used as decorator of a class method. + """ + @wraps(f) + def wrap(*args, **kwargs): + + # Here args[0] will hold self & kwargs will hold gid,sid,did + self = args[0] + self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( + kwargs['sid'] + ) + self.conn = self.manager.connection(did=kwargs['did']) + # If DB not connected then return error to browser + if not self.conn.connected(): + return precondition_required( + gettext("Connection to the server has been lost!") + ) + self.datlastsysoid = self.manager.db_info[ + kwargs['did']]['datlastsysoid'] + + # Set template path for sql scripts + self.template_path = self.template_initial + '/' + ( + self.ppas_template_path(self.manager.version) + if self.manager.server_type == 'ppas' else + self.pg_template_path(self.manager.version) + ) + + return f(*args, **kwargs) + + return wrap + + +class ViewNode(PGChildNodeView, VacuumSettings): + """ + This class is responsible for generating routes for view node. + + Methods: + ------- + * __init__(**kwargs) + - Method is used to initialize the ViewNode and it's base view. + + * module_js() + - Request handler for module.js routes for the view node module + javascript, which returns javscript for this module. + + * list() + - This function is used to list all the view nodes within the + collection. + + * nodes() + - This function will used to create all the child node within the + collection, Here it will create all the view node. + + * properties(gid, sid, did, scid) + - This function will show the properties of the selected view node. + + * create(gid, sid, did, scid) + - This function will create the new view object. + + * update(gid, sid, did, scid) + - This function will update the data for the selected view node. + + * delete(self, gid, sid, scid): + - This function will drop the view object + + * msql(gid, sid, did, scid) + - This function is used to return modified SQL for the selected view + node. + + * get_sql(data, scid) + - This function will generate sql from model data + + * sql(gid, sid, did, scid): + - This function will generate sql to show it in sql pane for the view + node. + + * dependency(gid, sid, did, scid): + - This function will generate dependency list show it in dependency + pane for the selected view node. + + * dependent(gid, sid, did, scid): + - This function will generate dependent list to show it in dependent + pane for the selected view node. + """ + node_type = view_blueprint.node_type + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'}, + {'type': 'int', 'id': 'did'}, + {'type': 'int', 'id': 'scid'} + ] + ids = [ + {'type': 'int', 'id': 'vid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'children': [{ + 'get': 'children' + }], + 'delete': [{'delete': 'delete'}], + 'refresh_data': [{'put': 'refresh_data'}, {'put': 'refresh_data'}], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'sql': [{'get': 'sql'}], + 'msql': [{'get': 'msql'}, {'get': 'msql'}], + 'stats': [{'get': 'statistics'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'module.js': [{}, {}, {'get': 'module_js'}], + 'configs': [{'get': 'configs'}], + 'get_tblspc': [{'get': 'get_tblspc'}, {'get': 'get_tblspc'}], + 'get_table_vacuum': [ + {'get': 'get_table_vacuum'}, + {'get': 'get_table_vacuum'}], + 'get_toast_table_vacuum': [ + {'get': 'get_toast_table_vacuum'}, + {'get': 'get_toast_table_vacuum'}] + }) + + def __init__(self, *args, **kwargs): + """ + Initialize the variables used by methods of ViewNode. + """ + + super(ViewNode, self).__init__(*args, **kwargs) + + self.manager = None + self.conn = None + self.template_path = None + self.template_initial = 'view' + + @staticmethod + def ppas_template_path(ver): + """ + Returns the template path for PPAS servers. + """ + return 'ppas/9.3_plus' + + @staticmethod + def pg_template_path(ver): + """ + Returns the template path for PostgreSQL servers. + """ + if ver >= 90400: + return 'pg/9.4_plus' + elif ver >= 90300: + return 'pg/9.3_plus' + elif ver >= 90200: + return 'pg/9.2_plus' + elif ver >= 90100: + return 'pg/9.1_plus' + return 'pg/9.1_plus' + + @check_precondition + def list(self, gid, sid, did, scid): + """ + Fetches all views properties and render into properties tab + """ + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql']), scid=scid) + status, res = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + return ajax_response( + response=res['rows'], + status=200 + ) + + @check_precondition + def nodes(self, gid, sid, did, scid): + """ + Lists all views under the Views Collection node + """ + res = [] + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql']), scid=scid) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=rset) + + for row in rset['rows']: + res.append( + self.blueprint.generate_browser_node( + row['oid'], + scid, + row['name'], + icon="icon-view" + )) + + return make_json_response( + data=res, + status=200 + ) + + def parse_views_privileges(self, db_privileges): + """ + This function forms a separate list of grantable + and non grantable privileges. + """ + acl = {'grantor': db_privileges['grantor'], + 'grantee': db_privileges['grantee'], + 'privileges': [] + } + + privileges = [] + for idx, priv in enumerate(db_privileges['privileges']): + if db_privileges['grantable'][idx]: + privileges.append({"privilege_type": priv, + "privilege": True, + "with_grant": True + }) + else: + privileges.append({"privilege_type": priv, + "privilege": True, + "with_grant": False + }) + + acl['privileges'] = privileges + + return acl + + @check_precondition + def properties(self, gid, sid, did, scid, vid): + """ + Fetches the properties of an individual view + and render in the properties tab + """ + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql'] + ), vid=vid, datlastsysoid=self.datlastsysoid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join( + [self.template_path, 'sql/acl.sql']), vid=vid) + status, dataclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in dataclres['rows']: + priv = self.parse_views_privileges(row) + if row['deftype'] in res['rows'][0]: + res['rows'][0][row['deftype']].append(priv) + else: + res['rows'][0][row['deftype']] = [priv] + + result = res['rows'][0] + + # sending result to formtter + frmtd_reslt = self.formatter(result) + + # merging formated result with main result again + result.update(frmtd_reslt) + + return ajax_response( + response=result, + status=200 + ) + + @staticmethod + def formatter(result): + """ This function formats output for security label & variables""" + frmtd_result = dict() + sec_lbls = [] + if 'seclabels' in result and result['seclabels'] is not None: + for sec in result['seclabels']: + import re + sec = re.search(r'([^=]+)=(.*$)', sec) + sec_lbls.append({ + 'provider': sec.group(1), + 'security_label': sec.group(2) + }) + + frmtd_result.update({"seclabels": sec_lbls}) + return frmtd_result + + @check_precondition + def create(self, gid, sid, did, scid): + """ + This function will create a new view object + """ + required_args = [ + 'name', + 'definition' + ] + + data = request.form if request.form else \ + json.loads(request.data.decode()) + for arg in required_args: + if arg not in data: + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter (%s)." % arg + ) + ) + + SQL = self.getSQL(gid, sid, data) + try: + if SQL and SQL.strip('\n') and SQL.strip(' '): + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join( + [self.template_path, 'sql/view_id.sql']), data=data) + status, view_id = self.conn.execute_scalar(SQL) + return jsonify( + node=self.blueprint.generate_browser_node( + view_id, + scid, + data['name'], + icon="icon-view" + ) + ) + else: + return make_json_response( + success=1, + info=gettext("Nothing to update"), + data=SQL, + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def update(self, gid, sid, did, scid, vid): + """ + This function will update a view object + """ + data = request.form if request.form else \ + json.loads(request.data.decode()) + SQL = self.getSQL(gid, sid, data, vid) + try: + if SQL and SQL.strip('\n') and SQL.strip(' '): + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join( + [self.template_path, 'sql/view_id.sql']), data=data) + status, res_data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + view_id = res_data['rows'][0]['oid'] + new_view_name = res_data['rows'][0]['relname'] + if vid != view_id: + return jsonify( + node=self.blueprint.generate_browser_node( + view_id, + scid, + new_view_name, + icon="icon-view" + ) + ) + else: + return make_json_response( + success=1, + info=gettext("Nothing to update"), + data=SQL + ) + else: + return make_json_response( + success=1, + info=gettext("Nothing to update"), + data=SQL + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, vid): + """ + This function will drop a view object + """ + + # Below will decide if it's simple drop or drop with cascade call + cascade = True if self.cmd == 'delete' else False + + try: + + # Get name for view from did + SQL = render_template("/".join( + [self.template_path, 'sql/delete.sql']), vid=vid) + status, res_data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res_data) + + # drop view + SQL = render_template("/".join( + [self.template_path, 'sql/delete.sql']), + nspname=res_data['rows'][0]['nspname'], + name=res_data['rows'][0]['name'], cascade=cascade + ) + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info=gettext("View dropped"), + data={ + 'id': vid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + def _get_schema(self, scid): + """ + Returns Schema Name from its OID. + + Args: + scid: Schema Id + """ + SQL = render_template("/".join([self.template_path, + 'sql/get_schema.sql']), scid=scid) + + status, schema_name = self.conn.execute_scalar(SQL) + + if not status: + return internal_server_error(errormsg=schema_name) + + return schema_name + + @check_precondition + def msql(self, gid, sid, did, scid, vid=None): + """ + This function returns modified SQL + """ + data = {} + for k, v in request.args.items(): + try: + data[k] = json.loads(v) + except ValueError: + data[k] = v + + SQL = self.getSQL(gid, sid, data, vid) + SQL = SQL.strip('\n') + if(SQL): + return make_json_response( + data=SQL, + status=200 + ) + else: + return make_json_response( + data=gettext("-- Nothing changed"), + status=200 + ) + + @staticmethod + def parse_privileges(str_privileges, object_type='VIEW'): + """Parse Privileges.""" + db_privileges = { + 'a': 'INSERT', + 'r': 'SELECT', + 'w': 'UPDATE', + 'd': 'DELETE', + 'D': 'TRUNCATE', + 'x': 'REFERENCES', + 't': 'TRIGGER' + } + privileges = [] + for priv in str_privileges: + priv_with_grant = [] + priv_without_grant = [] + for privilege in priv['privileges']: + if privilege['with_grant']: + priv_with_grant.append( + db_privileges[privilege['privilege_type']]) + elif privilege['privilege']: + priv_without_grant.append( + db_privileges[privilege['privilege_type']]) + + # If we have all acl then just return all + if len(priv_with_grant) == len(db_privileges): + priv_with_grant = ['ALL'] + if len(priv_without_grant) == len(db_privileges): + priv_without_grant = ['ALL'] + + # Server Level validation + if 'grantee' in priv: + privileges.append( + { + 'grantee': priv['grantee'] if 'grantee' in priv else '', + 'with_grant': priv_with_grant, + 'without_grant': priv_without_grant + } + ) + else: + return '' + return privileges + + def getSQL(self, gid, sid, data, vid=None): + """ + This function will generate sql from model data + """ + try: + if vid is not None: + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql']), + vid=vid, + datlastsysoid=self.datlastsysoid + ) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + old_data = res['rows'][0] + + if 'name' not in data: + data['name'] = res['rows'][0]['name'] + if 'schema' not in data: + data['schema'] = res['rows'][0]['schema'] + + key = 'datacl' + if key in data and data[key] is not None: + if 'added' in data[key]: + data[key]['added'] = self.parse_privileges( + data[key]['added']) + if 'changed' in data[key]: + data[key]['changed'] = self.parse_privileges( + data[key]['changed']) + if 'deleted' in data[key]: + data[key]['deleted'] = self.parse_privileges( + data[key]['deleted']) + try: + SQL = render_template("/".join( + [self.template_path, 'sql/update.sql']), data=data, + o_data=old_data, conn=self.conn) + except Exception as e: + return internal_server_error(errormsg=str(e)) + else: + required_args = [ + 'name', + 'schema', + 'definition' + ] + for arg in required_args: + if arg not in data: + return " -- definition incomplete" + + # Get Schema Name from its OID. + if 'schema' in data and isinstance(data['schema'], int): + data['schema'] = self._get_schema(data['schema']) + + if 'datacl' in data and data['datacl'] is not None: + data['datacl'] = self.parse_privileges(data['datacl']) + SQL = render_template("/".join( + [self.template_path, 'sql/create.sql']), data=data) + if data['definition']: + SQL += "\n" + SQL += render_template("/".join( + [self.template_path, 'sql/grant.sql']), data=data) + return SQL + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + def get_index_column_details(self, idx, data): + """ + This functional will fetch list of column details for index + + Args: + idx: Index OID + data: Properties data + + Returns: + Updated properties data with column details + """ + + self.index_temp_path = 'index' + SQL = render_template("/".join([self.index_temp_path, + 'sql/9.1_plus/column_details.sql']), idx=idx) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=rset) + + # 'attdef' comes with quotes from query so we need to strip them + # 'options' we need true/false to render switch ASC(false)/DESC(true) + columns = [] + cols = [] + for row in rset['rows']: + + # We need all data as collection for ColumnsModel + cols_data = { + 'colname': row['attdef'].strip('"'), + 'collspcname': row['collnspname'], + 'op_class': row['opcname'], + } + if row['options'][0] == 'DESC': + cols_data['sort_order'] = True + columns.append(cols_data) + + # We need same data as string to display in properties window + # If multiple column then separate it by colon + cols_str = row['attdef'] + if row['collnspname']: + cols_str += ' COLLATE ' + row['collnspname'] + if row['opcname']: + cols_str += ' ' + row['opcname'] + if row['options'][0] == 'DESC': + cols_str += ' DESC' + cols.append(cols_str) + + # Push as collection + data['columns'] = columns + # Push as string + data['cols'] = ', '.join(cols) + + return data + + def get_trigger_column_details(self, tid, clist): + """ + This function will fetch list of column for trigger + + Args: + tid: Table OID + clist: List of columns + + Returns: + Updated properties data with column + """ + + self.trigger_temp_path = 'schema/trigger' + SQL = render_template("/".join([self.trigger_temp_path, + 'get_columns.sql']), + tid=tid, clist=clist) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=rset) + # 'tgattr' contains list of columns from table used in trigger + columns = [] + + for row in rset['rows']: + columns.append({'column': row['name']}) + + return columns + + def get_rule_sql(self, vid): + """ + Get all non system rules of view node, + generate their sql and render + into sql tab + """ + + self.rule_temp_path = 'rules' + SQL_data = '' + SQL = render_template("/".join( + [self.rule_temp_path, 'sql/properties.sql']), tid=vid) + + status, data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=data) + + for rule in data['rows']: + + # Generate SQL only for non system rule + if rule['name'] != '_RETURN': + res = [] + SQL = render_template("/".join( + [self.rule_temp_path, 'sql/properties.sql']), + rid=rule['oid'] + ) + status, res = self.conn.execute_dict(SQL) + res = parse_rule_definition(res) + SQL = render_template("/".join( + [self.rule_temp_path, 'sql/create.sql']), + data=res, display_comments=True) + SQL_data += '\n' + SQL_data += SQL + return SQL_data + + def get_trigger_sql(self, vid): + """ + Get all trigger nodes associated with view node, + generate their sql and render + into sql tab + """ + + # Define template path + self.trigger_temp_path = 'trigger' + + SQL_data = '' + SQL = render_template("/".join( + [self.trigger_temp_path, 'sql/9.1_plus/properties.sql']), + tid=vid) + + status, data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=data) + + for trigger in data['rows']: + SQL = render_template("/".join( + [self.trigger_temp_path, 'sql/9.1_plus/properties.sql']), + tid=trigger['oid'], + tgrelid=vid + ) + + status, res = self.conn.execute_dict(SQL) + + res_rows = dict(res['rows'][0]) + if res_rows['tgnargs'] > 1: + # We know that trigger has more than 1 + # arguments, let's join them + res_rows['tgargs'] = ', '.join( + res_rows['tgargs']) + + if len(res_rows['tgattr']) > 1: + columns = ', '.join(res_rows['tgattr'].split(' ')) + res_rows['columns'] = self.get_trigger_column_details( + trigger['oid'], columns) + res_rows = trigger_definition(res_rows) + + SQL = render_template("/".join( + [self.trigger_temp_path, 'sql/9.1_plus/create.sql']), + data=res_rows, display_comments=True) + SQL_data += '\n' + SQL_data += SQL + + return SQL_data + + def get_index_sql(self, vid): + """ + Get all index associated with view node, + generate their sql and render + into sql tab + """ + + self.index_temp_path = 'index' + SQL_data = '' + SQL = render_template("/".join( + [self.index_temp_path, 'sql/9.1_plus/properties.sql']), tid=vid) + status, data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=data) + + for index in data['rows']: + res = [] + SQL = render_template("/".join( + [self.index_temp_path, 'sql/9.1_plus/properties.sql']), + idx=index['oid'], + tid=vid + ) + status, res = self.conn.execute_dict(SQL) + + data = dict(res['rows'][0]) + # Adding parent into data dict, will be using it while creating sql + data['schema'] = data['nspname'] + data['table'] = data['tabname'] + + # Add column details for current index + data = self.get_index_column_details(index['oid'], data) + + SQL = render_template("/".join( + [self.index_temp_path, 'sql/9.1_plus/create.sql']), + data=data, display_comments=True) + SQL_data += '\n' + SQL_data += SQL + return SQL_data + + @check_precondition + def sql(self, gid, sid, did, scid, vid): + """ + This function will generate sql to render into the sql panel + """ + + SQL_data = '' + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql']), + vid=vid, + datlastsysoid=self.datlastsysoid + ) + + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + result = res['rows'][0] + + # Fetch all privileges for view + SQL = render_template("/".join( + [self.template_path, 'sql/acl.sql']), vid=vid) + status, dataclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in dataclres['rows']: + priv = self.parse_views_privileges(row) + if row['deftype'] in res['rows'][0]: + res['rows'][0]['datacl'].append(priv) + else: + res['rows'][0]['datacl'] = [priv] + + result.update(res['rows'][0]) + if 'datacl' in result: + result['datacl'] = self.parse_privileges(result['datacl']) + + SQL = render_template("/".join( + [self.template_path, 'sql/create.sql']), + data=result, + conn=self.conn, + display_comments=True + ) + SQL += "\n" + SQL += render_template("/".join( + [self.template_path, 'sql/grant.sql']), data=result) + + SQL_data += SQL + SQL_data += self.get_rule_sql(vid) + SQL_data += self.get_trigger_sql(vid) + SQL_data += self.get_index_sql(vid) + + return ajax_response(response=SQL_data) + + @check_precondition + def get_tblspc(self, gid, sid, did, scid): + """ + This function to return list of tablespaces + """ + res = [] + try: + SQL = render_template( + "/".join([self.template_path, 'sql/get_tblspc.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in rset['rows']: + res.append( + {'label': row['spcname'], 'value': row['spcname']} + ) + + return make_json_response( + data=res, + status=200 + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def dependents(self, gid, sid, did, scid, vid): + """ + This function gets the dependents and returns an ajax response + for the view node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + vid: View ID + """ + dependents_result = self.get_dependents(self.conn, vid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, vid): + """ + This function gets the dependencies and returns an ajax response + for the view node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + vid: View ID + """ + dependencies_result = self.get_dependencies(self.conn, vid) + return ajax_response( + response=dependencies_result, + status=200 + ) + + +class MaterializedViewNode(ViewNode, VacuumSettings): + """ + This class is responsible for generating routes for + materialized view node. + + Methods: + ------- + * __init__(**kwargs) + - Method is used to initialize the MaterializedView + and it's base view. + + * module_js() + - This property defines (if javascript) exists for this node. + Override this property for your own logic + + * create(gid, sid, did, scid) + - Raise an error - we can not create a material view. + + * update(gid, sid, did, scid) + - This function will update the data for the selected material node + + * delete(self, gid, sid, scid): + - Raise an error - we can not delete a material view. + + * get_sql(data, scid) + - This function will generate sql from model data + + """ + + node_type = mview_blueprint.node_type + + def __init__(self, *args, **kwargs): + """ + Initialize the variables used by methods of ViewNode. + """ + + super(MaterializedViewNode, self).__init__(*args, **kwargs) + + self.template_initial = 'mview' + + @staticmethod + def pg_template_path(ver): + """ + Returns the template path for PostgreSQL servers. + """ + if ver >= 90300: + return 'pg/9.3_plus' + return 'pg/9.3_plus' + + def get_sql(self, gid, sid, data, scid, vid=None): + """ + This function will generate sql from model data + """ + if scid is None: + return bad_request('Cannot create a View!') + + return super(MaterializedViewNode, self).get_sql( + gid, sid, data, scid, vid) + + def getSQL(self, gid, sid, data, vid=None): + """ + This function will genrate sql from model data + """ + try: + if vid is not None: + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql']), + vid=vid, + datlastsysoid=self.datlastsysoid + ) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + old_data = res['rows'][0] + + if 'name' not in data: + data['name'] = res['rows'][0]['name'] + if 'schema' not in data: + data['schema'] = res['rows'][0]['schema'] + + # merge vacuum lists into one + data['vacuum_data'] = {} + data['vacuum_data']['changed'] = [] + data['vacuum_data']['reset'] = [] + + # table vacuum: separate list of changed and reset data for + if ('vacuum_table' in data): + if ('changed' in data['vacuum_table']): + for item in data['vacuum_table']['changed']: + if 'value' in item.keys(): + if item['value'] is None: + if old_data[item['name']] != item['value']: + data['vacuum_data']['reset'].append(item) + else: + if (old_data[item['name']] is None or + (float(old_data[item['name']]) != float(item['value']))): + data['vacuum_data']['changed'].append(item) + + if ('autovacuum_enabled' in data and + old_data['autovacuum_enabled'] is not None): + if (data['autovacuum_enabled'] != + old_data['autovacuum_enabled']): + data['vacuum_data']['changed'].append( + {'name': 'autovacuum_enabled', + 'value': data['autovacuum_enabled']}) + elif ('autovacuum_enabled' in data and 'autovacuum_custom' in data and + old_data['autovacuum_enabled'] is None and data['autovacuum_custom']): + data['vacuum_data']['changed'].append( + {'name': 'autovacuum_enabled', + 'value': data['autovacuum_enabled']}) + + # toast autovacuum: separate list of changed and reset data + if ('vacuum_toast' in data): + if ('changed' in data['vacuum_toast']): + for item in data['vacuum_toast']['changed']: + if 'value' in item.keys(): + toast_key = 'toast_'+item['name'] + item['name'] = 'toast.'+item['name'] + if item['value'] is None: + if old_data[toast_key] != item['value']: + data['vacuum_data']['reset'].append(item) + else: + if (old_data[toast_key] is None or + (float(old_data[toast_key]) != float(item['value']))): + data['vacuum_data']['changed'].append(item) + + if ('toast_autovacuum_enabled' in data and + old_data['toast_autovacuum_enabled'] is not None): + if (data['toast_autovacuum_enabled'] != + old_data['toast_autovacuum_enabled']): + data['vacuum_data']['changed'].append( + {'name': 'toast.autovacuum_enabled', + 'value': data['toast_autovacuum_enabled']}) + elif ('toast_autovacuum_enabled' in data and 'toast_autovacuum' in data and + old_data['toast_autovacuum_enabled'] is None and data['toast_autovacuum']): + data['vacuum_data']['changed'].append( + {'name': 'toast.autovacuum_enabled', + 'value': data['toast_autovacuum_enabled']}) + + key = 'datacl' + if key in data and data[key] is not None: + if 'added' in data[key]: + data[key]['added'] = self.parse_privileges( + data[key]['added']) + if 'changed' in data[key]: + data[key]['changed'] = self.parse_privileges( + data[key]['changed']) + if 'deleted' in data[key]: + data[key]['deleted'] = self.parse_privileges( + data[key]['deleted']) + + try: + SQL = render_template("/".join( + [self.template_path, 'sql/update.sql']), data=data, + o_data=old_data, conn=self.conn) + except Exception as e: + return internal_server_error(errormsg=str(e)) + else: + required_args = [ + 'name', + 'schema', + 'definition' + ] + for arg in required_args: + if arg not in data: + return " -- definition incomplete" + + # Get Schema Name from its OID. + if 'schema' in data and isinstance(data['schema'], int): + data['schema'] = self._get_schema(data['schema']) + + # merge vacuum lists into one + vacuum_table = [item for item in data['vacuum_table'] + if 'value' in item.keys() and + item['value'] is not None] + vacuum_toast = [ + {'name': 'toast.'+item['name'], 'value':item['value']} + for item in data['vacuum_toast'] + if 'value' in item.keys() and item['value'] is not None] + + # add table_enabled & toast_enabled settings + if ('autovacuum_custom' in data and data['autovacuum_custom']): + vacuum_table.append( + { + 'name': 'autovacuum_enabled', + 'value': str(data['autovacuum_enabled']) + } + ) + if ('toast_autovacuum' in data and data['toast_autovacuum']): + vacuum_table.append( + { + 'name': 'toast.autovacuum_enabled', + 'value': str(data['toast_autovacuum_enabled']) + } + ) + + # add vacuum_toast dict to vacuum_data only if + # table & toast's custom autovacuum is enabled + data['vacuum_data'] = (vacuum_table if ( + 'autovacuum_custom' in data and + data['autovacuum_custom'] is True + ) else []) + ( + vacuum_toast if ( + 'toast_autovacuum' in data and + data['toast_autovacuum'] is True + ) else []) + + if 'datacl' in data and data['datacl'] is not None: + data['datacl'] = self.parse_privileges(data['datacl']) + SQL = render_template("/".join( + [self.template_path, 'sql/create.sql']), data=data) + if data['definition']: + SQL += "\n" + SQL += render_template("/".join( + [self.template_path, 'sql/grant.sql']), data=data) + return SQL + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, vid): + """ + This function will generate sql to render into the sql panel + """ + + SQL_data = '' + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql']), + vid=vid, + datlastsysoid=self.datlastsysoid + ) + + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + result = res['rows'][0] + + # sending result to formtter + frmtd_reslt = self.formatter(result) + + # merging formated result with main result again + result.update(frmtd_reslt) + result['vacuum_table'] = self.parse_vacuum_data( + self.conn, result, 'table') + result['vacuum_toast'] = self.parse_vacuum_data( + self.conn, result, 'toast') + + # merge vacuum lists into one + vacuum_table = [item for item in result['vacuum_table'] + if 'value' in item.keys() and item['value'] is not None] + vacuum_toast = [ + {'name': 'toast.'+item['name'], 'value':item['value']} + for item in result['vacuum_toast'] if 'value' in item.keys() and item['value'] is not None] + + # add vacuum_toast dict to vacuum_data only if + # toast's autovacuum is enabled + if ('toast_autovacuum_enabled' in result and + result['toast_autovacuum_enabled'] is True): + result['vacuum_data'] = vacuum_table + vacuum_toast + else: + result['vacuum_data'] = vacuum_table + + # Fetch all privileges for view + SQL = render_template("/".join( + [self.template_path, 'sql/acl.sql']), vid=vid) + status, dataclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in dataclres['rows']: + priv = self.parse_views_privileges(row) + if row['deftype'] in res['rows'][0]: + res['rows'][0]['datacl'].append(priv) + else: + res['rows'][0]['datacl'] = [priv] + + result.update(res['rows'][0]) + if 'datacl' in result: + result['datacl'] = self.parse_privileges(result['datacl']) + + SQL = render_template("/".join( + [self.template_path, 'sql/create.sql']), + data=result, + conn=self.conn, + display_comments=True + ) + SQL += "\n" + SQL += render_template("/".join( + [self.template_path, 'sql/grant.sql']), data=result) + + SQL_data += SQL + SQL_data += self.get_rule_sql(vid) + SQL_data += self.get_trigger_sql(vid) + SQL_data += self.get_index_sql(vid) + SQL_data = SQL_data.strip('\n') + return ajax_response(response=SQL_data) + + @check_precondition + def get_table_vacuum(self, gid, sid, did, scid): + """ + Fetch the default values for autovacuum + fields, return an array of + - label + - name + - setting + values + """ + + res = self.get_vacuum_table_settings(self.conn) + return ajax_response( + response=res['rows'], + status=200 + ) + + @check_precondition + def get_toast_table_vacuum(self, gid, sid, did, scid): + """ + Fetch the default values for autovacuum + fields, return an array of + - label + - name + - setting + values + """ + res = self.get_vacuum_toast_settings(self.conn) + + return ajax_response( + response=res['rows'], + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, vid): + """ + Fetches the properties of an individual view + and render in the properties tab + """ + SQL = render_template("/".join( + [self.template_path, 'sql/properties.sql'] + ), vid=vid, datlastsysoid=self.datlastsysoid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join( + [self.template_path, 'sql/acl.sql']), vid=vid) + status, dataclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in dataclres['rows']: + priv = self.parse_views_privileges(row) + if row['deftype'] in res['rows'][0]: + res['rows'][0][row['deftype']].append(priv) + else: + res['rows'][0][row['deftype']] = [priv] + + result = res['rows'][0] + + # sending result to formtter + frmtd_reslt = self.formatter(result) + + # merging formated result with main result again + result.update(frmtd_reslt) + + result['vacuum_table'] = self.parse_vacuum_data( + self.conn, result, 'table') + result['vacuum_toast'] = self.parse_vacuum_data( + self.conn, result, 'toast') + + return ajax_response( + response=result, + status=200 + ) + + @check_precondition + def refresh_data(self, gid, sid, did, scid, vid): + """ + This function will refresh view object + """ + + # Below will decide if it's refresh data or refresh concurrently + data = request.form if request.form else json.loads(request.data.decode()) + is_concurrent = json.loads(data['concurrent']) + + try: + + # Fetch view name by view id + SQL = render_template("/".join( + [self.template_path, 'sql/get_view_name.sql']), vid=vid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Refresh view + SQL = render_template("/".join( + [self.template_path, 'sql/refresh.sql']), + name=res['rows'][0]['name'], + nspname=res['rows'][0]['schema'], is_concurrent=is_concurrent) + status, res_data = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res_data) + + return make_json_response( + success=1, + info=gettext("View refreshed"), + data={ + 'id': vid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + +ViewNode.register_node_view(view_blueprint) +MaterializedViewNode.register_node_view(mview_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/children/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/children/__init__.py new file mode 100644 index 000000000..3993ff3f7 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/children/__init__.py @@ -0,0 +1,12 @@ +""" +We will use the exisiting modules for creating children module under +materialize views. +""" +from pgadmin.browser.server_groups.servers.databases.schemas.tables.column \ + import blueprint as columns_module +from pgadmin.browser.server_groups.servers.databases.schemas.tables.indexes \ + import blueprint as indexes_modules +from pgadmin.browser.server_groups.servers.databases.schemas.tables.triggers \ + import blueprint as triggers_modules +from pgadmin.browser.server_groups.servers.databases.schemas.tables.rules \ + import blueprint as rules_modules diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/img/coll-mview.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/img/coll-mview.png new file mode 100644 index 0000000000000000000000000000000000000000..40e65a96e18004104b041b0ae32579b26ae97058 GIT binary patch literal 374 zcmV-+0g3*JP)PA(>hLAOE$2b!1V^ni|PnE{A)5-}!eBlsp2!8Jwv{ z_xxYN&Za98fNAM!r+Elb4K)_xh3TSloEv+sugkCnz_QX^u*q6^bxOdKRnRzD^9{rj2 z_}lVF@Af@;b@}P@d(WRgefI3xqo=p7KVP}!V)Uc`-T(gmd-%V5`%AU||Nn1)p?>Gh zn(Z&tPJa$N{=xgfzqUJn>TdojJ^s=A@Oy`SZ_IYR((AHW{03+NV@Z%-FoVOh8)+a; zlDE5yQ1zZ1Ae(`+z$3C4NPB>>+sSM@AS2(?#W6(Ua%g{~P=f-Gv+27P9V>QJ|4;U6 zbe!GKH+kPSMNh%0YD;wVPp!&p$=H2Qa>4_iC-Ws`4oVu`kXvDIe5l_eV|jwW;+5+S zYgy6~PYdy+-cS45)~k2Z!$WAAUct+ok^krC+MlVs+ppfyc`@F`nC<>l-VMq?t5r)} zBT7;dOH!?pi&B9UgOP!up{{|Eu910&p^25DrIo3vwt<D*x6OT+Cpd08n!IM#^LZ1F3M3y)72cH;)3)hB@w(<$ENtuI!+37X&3YKpe7)iO zo7EB_E>059WTrQES9;xXdidD%!K10kJRqPs&0k{Df9H%vu?(M!xtNs?&v|Ub)6*j$ zbyq+v$yxg5%?jQE!}Cc$KEG!_e82v_q}|_|69*1#=yHs8ZfyjDhri#K1C8xOdKRnaBToAO4>7 z;On9XZ+AU@dGYD<`_G?0efI3xZ-1%w|NsB(FVt^;p7P|y zjoU9bT=|i6;cMdQ&tb_QLRH3SlxI5?abofwq#PpGhn z3y3`waupO1o<6}vaKfZ%6BvUwB`{h}XxPzW6T>ijp+R<{)&<#R3sx-A(NkQ!Xcb#n z<0DHqpYzNNJzLm||5$yx0JK%L#5JNMC9x#cD!C{XNHG{07#ipr8tEDsh8P)GnHXD{ zm}(oCS{WG3d#ASwMMG|WN@iLmM1z4PSOZYCiIssFM8m1+p=*E|7(8A5T-G@yGywnx Cm9(({ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/css/mview.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/css/mview.css new file mode 100644 index 000000000..4782530e5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/css/mview.css @@ -0,0 +1,12 @@ +.icon-mview{ + background-image: url('{{ url_for('NODE-mview.static', filename='img/mview.png') }}') !important; + border-radius: 10px; + background-repeat: no-repeat; + align-content: center; + vertical-align: middle; + height: 1.3em; +} + +.sql_field_width_full { + width: 100%; +} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/js/mview.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/js/mview.js new file mode 100644 index 000000000..1772ca3fc --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/js/mview.js @@ -0,0 +1,313 @@ +define( + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'alertify', + 'pgadmin.browser', 'codemirror', 'pgadmin.browser.server.privilege'], + +function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) { + + /** + Create and add a view collection into nodes + @param {variable} label - Label for Node + @param {variable} type - Type of Node + @param {variable} columns - List of columns to + display under under properties. + */ + if (!pgBrowser.Nodes['coll-mview']) { + var mviews= pgAdmin.Browser.Nodes['coll-mview'] = + pgAdmin.Browser.Collection.extend({ + node: 'mview', + label: '{{ _("Materialized Views") }}', + type: 'coll-mview', + columns: ['name', 'owner'] + }); + } + + /** + Create and Add a View Node into nodes + @param {variable} parent_type - The list of nodes + under which this node to display + @param {variable} type - Type of Node + @param {variable} hasSQL - To show SQL tab + @param {variable} canDrop - Adds drop view option + in the context menu + @param {variable} canDropCascade - Adds drop Cascade + view option in the context menu + */ + if (!pgBrowser.Nodes['mview']) { + pgAdmin.Browser.Nodes['mview'] = pgAdmin.Browser.Node.extend({ + parent_type: ['schema', 'catalog'], + type: 'mview', + sqlAlterHelp: 'sql-altermaterializedview.html', + sqlCreateHelp: 'sql-creatematerializedview.html', + label: '{{ _("Materialized View") }}', + hasSQL: true, + hasDepends: true, + collection_type: 'coll-mview', + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + Init: function() { + + // Avoid mulitple registration of menus + if (this.initialized) + return; + + this.initialized = true; + + /** + Add "create view" menu option into context and object menu + for the following nodes: + coll-mview, view and schema. + @property {data} - Allow create view option on schema node or + system view nodes. + */ + pgBrowser.add_menus([{ + name: 'create_mview_on_coll', node: 'coll-mview', + module: this, applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 1, label: '{{ _("Materialized View...") }}', + icon: 'wcTabIcon icon-mview', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_mview', node: 'mview', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 1, label: '{{ _("Materialized View...") }}', + icon: 'wcTabIcon icon-mview', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_mview', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 18, label: '{{ _("Materialized View...") }}', + icon: 'wcTabIcon icon-mview', data: {action: 'create', check: false}, + enable: 'canCreate' + },{ + name: 'refresh_mview', node: 'mview', module: this, category: 'Refresh view', + applies: ['object', 'context'], callback: 'refresh_mview', icon: 'fa fa-refresh', + priority: 1, label: '{{ _("Refresh data") }}', data: {concurrent: false} + },{ + name: 'refresh_mview_concurrent', node: 'mview', module: this, + category: 'Refresh view', + applies: ['object', 'context'], callback: 'refresh_mview', icon: 'fa fa-refresh', + priority: 2, label: '{{ _("Refresh concurrently") }}', data: {concurrent: true} + } + ]); + }, + + /** + Define model for the view node and specify the + properties of the model in schema. + */ + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + var schemaLabel = args.node_info.schema.label; + this.set({'schema': schemaLabel}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'owner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + defaults: { + spcname: 'pg_default', + toast_autovacuum_enabled: false, + autovacuum_enabled: false + }, + schema: [{ + id: 'name', label: '{{ _("Name") }}', cell: 'string', + type: 'text', disabled: 'inSchema' + }, + { + id: 'oid', label:'{{ _("OID") }}', cell: 'string', + type: 'text', disabled: true, mode: ['properties'] + }, + { + id: 'owner', label:'{{ _("Owner") }}', cell: 'string', + control: 'node-list-by-name', select2: { allowClear: false }, + node: 'role', disabled: 'inSchema' + }, + { + id: 'schema', label:'{{ _("Schema") }}', cell: 'string', first_empty: false, + control: 'node-list-by-name', type: 'text', cache_level: 'database', + node: 'schema', mode: ['create', 'edit'], disabled: 'inSchema', select2: { allowClear: false } + }, + { + id: 'system_view', label:'{{ _("System view?") }}', cell: 'string', + type: 'switch', disabled: true, mode: ['properties'], + }, + { + id: 'acl', label: '{{ _("ACL") }}', + mode: ['properties'], type: 'text' + }, + { + id: 'comment', label:'{{ _("Comment") }}', cell: 'string', + type: 'multiline' + }, + { + id: 'definition', label:'{{ _("") }}', cell: 'string', + type: 'text', mode: ['create', 'edit'], group: 'Definition', + control: Backform.SqlFieldControl, extraClasses:['sql_field_width_full'] + }, + // Add Privilege Control + { + id: 'datacl', label: '{{ _("Privileges") }}', + model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}), uniqueCol : ['grantee'], + editable: false, type: 'collection', group: '{{ _("Security") }}', + mode: ['edit', 'create'], canAdd: true, canDelete: true, + control: 'unique-col-collection', priority: 3 + }, + + // Add Security Labels Control + { + id: 'seclabels', label: '{{ _("Security Labels") }}', + model: Backform.SecurityModel, editable: false, type: 'collection', + canEdit: false, group: '{{ _("Security") }}', canDelete: true, + mode: ['edit', 'create'], canAdd: true, + control: 'unique-col-collection', uniqueCol : ['provider'] + }, + { + id: 'with_data', label: '{{ _("With Data") }}', + group: '{{ _("Storage") }}', mode: ['edit', 'create'], + type: 'switch', + }, + { + id: 'spcname', label: '{{ _("Tablespace") }}', cell: 'string', + type: 'text', group: '{{ _("Storage") }}', first_empty: false, + control: 'node-list-by-name', node: 'tablespace', select2: { allowClear: false }, + filter: function(m) { + if (m.label == "pg_global") return false; + else return true; + } + }, + { + id: 'fillfactor', label: '{{ _("Fill Factor") }}', + group: '{{ _("Storage") }}', mode: ['edit', 'create'], + type: 'integer' + }, + { + type: 'nested', control: 'tab', id: 'materialization', + label: '{{ _("Materialization") }}', mode: ['edit', 'create'], + group: '{{ _("Storage") }}', + schema: Backform.VacuumSettingsSchema + }, + ], + validate: function(keys) { + + // Triggers specific error messages for fields + var err = {}, + errmsg, + field_name = this.get('name'), + field_def = this.get('definition'); + if (_.indexOf(keys, 'autovacuum_enabled') != -1 || + _.indexOf(keys, 'toast_autovacuum_enabled') != -1 ) + return null; + + if (_.isUndefined(field_name) || _.isNull(field_name) || + String(field_name).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _("Please specify name.") }}'; + errmsg = errmsg || err['name']; + this.errorModel.set('name', errmsg); + return errmsg; + }else{ + this.errorModel.unset('name'); + } + if (_.isUndefined(field_def) || _.isNull(field_def) || + String(field_def).replace(/^\s+|\s+$/g, '') == '') { + err['definition'] = '{{ _("Please enter function definition.") }}'; + errmsg = errmsg || err['definition']; + this.errorModel.set('definition', errmsg); + return errmsg; + }else{ + this.errorModel.unset('definition'); + } + return null; + }, + // We will disable everything if we are under catalog node + inSchema: function() { + if(this.node_info && 'catalog' in this.node_info) + { + return true; + } + return false; + } + + }), + + /** + Show or hide create view menu option on parent node + and hide for system view in catalogs. + */ + canCreate: function(itemData, item, data) { + + // If check is false then, we will allow create menu + if (data && data.check === false) + return true; + + var t = pgBrowser.tree, i = item, d = itemData; + + // To iterate over tree to check parent node + while (i) { + + // If it is schema then allow user to create view + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-mview' == d._type) { + + // Check if we are not child of view + prev_i = t.hasParent(i) ? t.parent(i) : null; + prev_d = prev_i ? t.itemData(prev_i) : null; + if( prev_d._type == 'catalog') { + return false; + } else { + return true; + } + } + i = t.hasParent(i) ? t.parent(i) : null; + d = i ? t.itemData(i) : null; + } + + // by default we do not want to allow create menu + return true; + + }, + refresh_mview: function(args) { + var input = args || {}; + obj = this, + t = pgBrowser.tree, + i = input.item || t.selected(), + d = i && i.length == 1 ? t.itemData(i) : undefined; + + if (!d) + return false; + + // Make ajax call to refresh mview data + $.ajax({ + url: obj.generate_url(i, 'refresh_data' , d, true), + type: 'PUT', + data: {'concurrent': args.concurrent}, + dataType: "json", + success: function(res) { + if (res.success == 1) { + alertify.success('View refreshed successfully'); + } + else { + alertify.alert( + 'Error refreshing view', + res.data.result + ); + } + }, + error: function(e) { + var errmsg = $.parseJSON(e.responseText); + alertify.alert('Error refreshing view', errmsg.errormsg); + } + }); + + } + }); + } + + return pgBrowser.Nodes['coll-mview']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/acl.sql new file mode 100644 index 000000000..0c1bd6c84 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/acl.sql @@ -0,0 +1,41 @@ +{#============================Get ACLs=========================#} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, + d.grantor, + d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON + (cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'm' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/create.sql new file mode 100644 index 000000000..d8cac277b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/create.sql @@ -0,0 +1,41 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} +{% if(data.fillfactor or data['vacuum_data']|length > 0) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if data['autovacuum_enabled'] or data['toast_autovacuum_enabled'] or data['vacuum_data']|length > 0 %},{{ '\r' }}{% endif %} +{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if loop.index > 1%}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% endif %} +{% endfor %} + +) +{% endif %} +{% if data.spcname %}TABLESPACE {{ data.spcname }} +{% endif %}AS +{{ data.definition.rstrip(';') }} +{% if data.with_data %} +WITH DATA; +{% else %} +WITH NO DATA; +{% endif %} +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} + +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/delete.sql new file mode 100644 index 000000000..cf667fc55 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# =================== Drop/Cascade materialized view by name ====================#} +{% if vid %} +SELECT + c.relname As name, + nsp.nspname +FROM + pg_class c +LEFT JOIN pg_namespace nsp ON c.relnamespace = nsp.oid +WHERE + c.relfilenode = {{ vid }}; +{% elif (name and nspname) %} +DROP MATERIALIZED VIEW {{ conn|qtIdent(nspname, name) }} {% if cascade %} CASCADE {% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_schema.sql new file mode 100644 index 000000000..bcc3d1cc3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name =====#} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_view_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_view_name.sql new file mode 100644 index 000000000..29ca63872 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/get_view_name.sql @@ -0,0 +1,11 @@ +{# ===== get view name against view id ==== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname AS schema +FROM + pg_class c + LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +WHERE + c.oid = {{vid}} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/grant.sql new file mode 100644 index 000000000..cff9d3126 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ==== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# We will generate Security Label SQL using macro #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{% endfor %}{% endif %} +{% if data.datacl %}{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/properties.sql new file mode 100644 index 000000000..8a705225d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/properties.sql @@ -0,0 +1,111 @@ +{# ========================== Fetch Materialized View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + c.relispopulated AS with_data, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relacl, + nsp.nspname as schema, + pg_get_userbyid(c.relowner) AS owner, + description AS comment, + pg_get_viewdef(c.oid, true) AS definition, + {# ============= Checks if it is system view ================ #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (CASE WHEN (substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') THEN true ELSE false END) AS autovacuum_enabled, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (CASE WHEN (substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') THEN true ELSE false END) AS toast_autovacuum_enabled, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + c.reloptions AS reloptions, tst.reloptions AS toast_reloptions, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, + (CASE WHEN (substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)')) = 'true' THEN true ELSE false END) AS autovacuum_custom, + (CASE WHEN (substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)')) = 'true' THEN true ELSE false END) AS toast_autovacuum +FROM + pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'm'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/refresh.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/refresh.sql new file mode 100644 index 000000000..c157036b3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/refresh.sql @@ -0,0 +1,4 @@ +{#=== refresh mat view [concurrenlty] ===#} +{% if name and nspname %} +REFRESH MATERIALIZED VIEW {% if is_concurrent %}CONCURRENTLY{% endif %} {{ conn|qtIdent(nspname, name) }}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/update.sql new file mode 100644 index 000000000..e366fdee6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/update.sql @@ -0,0 +1,216 @@ +{# ===================== Update View ===================#} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{%- if data -%} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{# ===== Rename mat view ===== #} +{% if data.name and data.name != o_data.name %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; + +{% endif %} +{# ===== Alter schema view ===== #} +{% if data.schema and data.schema != o_data.schema %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(o_data.schema, view_name ) }} + SET SCHEMA {{ conn|qtIdent(data.schema) }}; + +{% endif %} +{# ===== Alter Table owner ===== #} +{% if data.owner and data.owner != o_data.owner %} +ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; + +{% endif %} +{# ===== First Drop and then create mat view ===== #} +{% if def and def != o_data.definition.rstrip(';') %} +DROP MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +{% if data.fillfactor or (data['vacuum_data']['changed']|length > 0 ) %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if data['vacuum_data']['changed']|length > 0 %},{% endif %}{{ '\r' }} +{% endif %} +{% if data['vacuum_data']['changed']|length > 0 %} +{% for field in data['vacuum_data']['changed'] %} + {{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endfor %} +{% endif %} +) +{% endif %} + AS +{{ def }} +{% if data.with_data is defined %} + WITH {{ 'DATA' if data.with_data else 'NO DATA' }}; + +{% elif o_data.with_data %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcoid and o_data.spcoid != data.spcoid -%} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET TABLESPACE {{ data.spcoid }}; + +{% endif %} +{# ======= SET/RESET Fillfactor ========= #} +{% if data.fillfactor and o_data.fillfactor != data.fillfactor %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( + FILLFACTOR +); + +{% endif %} +{# ===== Check for with_data property ===== #} +{% if data.with_data is defined and o_data.with_data|lower != data.with_data|lower %} +REFRESH MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} WITH{{ ' NO' if data.with_data|lower == 'false' else '' }} DATA; + +{% endif %} +{# ===== Check for Table tab properties ===== #} +{% if ((data.autovacuum_custom is defined and data.autovacuum_custom|lower == 'false') or +(data.toast_autovacuum is defined and data.toast_autovacuum|lower == 'false') +) %} +{% if data.autovacuum_custom|lower == 'false' %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( + autovacuum_enabled, + autovacuum_vacuum_threshold, + autovacuum_analyze_threshold, + autovacuum_vacuum_scale_factor, + autovacuum_analyze_scale_factor, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_cost_limit, + autovacuum_freeze_min_age, + autovacuum_freeze_max_age, + autovacuum_freeze_table_age +); + +{% if data.toast_autovacuum is defined and data.toast_autovacuum|lower != 'false' %} +{% if('vacuum_toast' in data and data['vacuum_toast']['changed']|length > 0) %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} SET( +{% for field in data['vacuum_toast']['changed'] %} +{% if field.value != None %} + {{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endif %} +{% endfor %} +); + +{% endif %} +{% endif %} + +{% endif %} +{% if data.toast_autovacuum|lower == 'false' %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( + toast.autovacuum_enabled, + toast.autovacuum_vacuum_threshold, + toast.autovacuum_analyze_threshold, + toast.autovacuum_vacuum_scale_factor, + toast.autovacuum_analyze_scale_factor, + toast.autovacuum_vacuum_cost_delay, + toast.autovacuum_vacuum_cost_limit, + toast.autovacuum_freeze_min_age, + toast.autovacuum_freeze_max_age, + toast.autovacuum_freeze_table_age +); + +{% if data.autovacuum_custom is defined and data.autovacuum_custom|lower != 'false' %} +{% if('vacuum_table' in data and data['vacuum_table']['changed']|length > 0) %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} SET( +{% for field in data['vacuum_table']['changed'] %} +{% if field.value != None %} + {{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endif %} +{% endfor %} +); + +{% endif %} +{% endif %} +{% endif %}{#-- toast_endif ends --#} + +{% else %} +{% if data['vacuum_data']['reset']|length == 0 and +data['vacuum_data']['changed']|length == 0 and data['settings']|length > 0 %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +SET( +{% for field in data['settings'] %} + {{ field }} = {{ data['settings'][field]|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endfor %} +); + +{% endif %} +{% if(data['vacuum_data']['changed']|length > 0) %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} +SET( +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} + {{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endif %} +{% endfor %} +); + +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( +{% for field in data['vacuum_data']['reset'] %} + {{ field.name }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endfor %} +); +{% endif %} + +{% endif %}{# ===== End check for custom autovaccum ===== #} +{% endif %}{# ===== End block for check data definition ===== #} +{% set old_comment = o_data.comment|default('', true) %} +{% if (data.comment is defined and (data.comment != old_comment)) %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{# ============= The SQL generated below will change privileges ============= #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed -%} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{%- endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# ============== The SQL generated below will change Security Label ========= #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/view_id.sql new file mode 100644 index 000000000..487e59e64 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/pg/9.3_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ==== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/acl.sql new file mode 100644 index 000000000..0c1bd6c84 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/acl.sql @@ -0,0 +1,41 @@ +{#============================Get ACLs=========================#} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, + d.grantor, + d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON + (cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'm' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/create.sql new file mode 100644 index 000000000..041f69d9e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/create.sql @@ -0,0 +1,47 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} +{% if(data.fillfactor or data['autovacuum_enabled'] or data['toast_autovacuum_enabled']) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if data['autovacuum_enabled'] or data['toast_autovacuum_enabled'] or data['vacuum_data']|length > 0 %},{{ '\r' }}{% endif %} +{% endif %} +{% if data['autovacuum_enabled'] %} + autovacuum_enabled = {{ data['autovacuum_enabled']|lower }}{% if data['toast_autovacuum_enabled'] or data['vacuum_data']|length > 0 %},{{ '\r' }}{% endif %} +{% endif %} +{% if data['toast_autovacuum_enabled'] %} + {{ 'toast.autovacuum_enabled' }} = {{ data['toast_autovacuum_enabled']|lower }}{% if data['vacuum_data']|length > 0 %},{{ '\r' }}{% endif %} +{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if loop.index > 1%}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% endif %} +{% endfor %} + +) +{% endif %} +{% if data.spcname %}TABLESPACE {{ data.spcname }} +{% endif %}AS +{{ data.definition.rstrip(';') }} +{% if data.with_data %} +WITH DATA; +{% else %} +WITH NO DATA; +{% endif %} +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} + +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/delete.sql new file mode 100644 index 000000000..cf667fc55 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# =================== Drop/Cascade materialized view by name ====================#} +{% if vid %} +SELECT + c.relname As name, + nsp.nspname +FROM + pg_class c +LEFT JOIN pg_namespace nsp ON c.relnamespace = nsp.oid +WHERE + c.relfilenode = {{ vid }}; +{% elif (name and nspname) %} +DROP MATERIALIZED VIEW {{ conn|qtIdent(nspname, name) }} {% if cascade %} CASCADE {% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_schema.sql new file mode 100644 index 000000000..7244ed345 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name =====#} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_view_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_view_name.sql new file mode 100644 index 000000000..29ca63872 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/get_view_name.sql @@ -0,0 +1,11 @@ +{# ===== get view name against view id ==== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname AS schema +FROM + pg_class c + LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +WHERE + c.oid = {{vid}} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/grant.sql new file mode 100644 index 000000000..cff9d3126 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ==== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# We will generate Security Label SQL using macro #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{% endfor %}{% endif %} +{% if data.datacl %}{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/properties.sql new file mode 100644 index 000000000..8a705225d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/properties.sql @@ -0,0 +1,111 @@ +{# ========================== Fetch Materialized View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + c.relispopulated AS with_data, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relacl, + nsp.nspname as schema, + pg_get_userbyid(c.relowner) AS owner, + description AS comment, + pg_get_viewdef(c.oid, true) AS definition, + {# ============= Checks if it is system view ================ #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (CASE WHEN (substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') THEN true ELSE false END) AS autovacuum_enabled, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (CASE WHEN (substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') THEN true ELSE false END) AS toast_autovacuum_enabled, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + c.reloptions AS reloptions, tst.reloptions AS toast_reloptions, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, + (CASE WHEN (substring(array_to_string(c.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)')) = 'true' THEN true ELSE false END) AS autovacuum_custom, + (CASE WHEN (substring(array_to_string(tst.reloptions, ',') + FROM 'autovacuum_enabled=([a-z|0-9]*)')) = 'true' THEN true ELSE false END) AS toast_autovacuum +FROM + pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'm'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/refresh.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/refresh.sql new file mode 100644 index 000000000..c157036b3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/refresh.sql @@ -0,0 +1,4 @@ +{#=== refresh mat view [concurrenlty] ===#} +{% if name and nspname %} +REFRESH MATERIALIZED VIEW {% if is_concurrent %}CONCURRENTLY{% endif %} {{ conn|qtIdent(nspname, name) }}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/update.sql new file mode 100644 index 000000000..b577ce7e3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/update.sql @@ -0,0 +1,179 @@ +{# ===================== Update View ===================#} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{%- if data -%} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{# ===== Rename mat view ===== #} +{% if data.name and data.name != o_data.name %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; + +{% endif %} +{# ===== Alter schema view ===== #} +{% if data.schema and data.schema != o_data.schema %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(o_data.schema, view_name ) }} + SET SCHEMA {{ conn|qtIdent(data.schema) }}; + +{% endif %} +{# ===== Alter Table owner ===== #} +{% 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 data['vacuum_data']['reset']|length == 0 and +data['vacuum_data']['changed']|length == 0 and data['settings']|length > 0 %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +SET( +{% for field in data['settings'] %} + {{ field }} = {{ data['settings'][field]|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endfor %} +); + +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( +{% for field in data['vacuum_data']['reset'] %} + {{ field.name }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endfor %} +); +{% endif %} +{# ===== First Drop and then create mat view ===== #} +{% if def and def != o_data.definition.rstrip(';') %} +{% if data.fillfactor or ( data['vacuum_data']['changed']|length > 0 ) %} +DROP MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if data['vacuum_data']['changed']|length > 0 %},{% endif %}{{ '\r' }} +{% endif %} +{% if data['vacuum_data']['changed']|length > 0 %} +{% for field in data['vacuum_data']['changed'] %} + {{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endfor %} +{% endif %} +) + AS +{{ def }} +{% if data.with_data %} + WITH DATA; + +{% else %} + WITH NO DATA; + +{% endif %} +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcoid and o_data.spcoid != data.spcoid -%} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET TABLESPACE {{ data.spcoid }}; + +{% endif %} +{# ======= SET/RESET Fillfactor ========= #} +{% if data.fillfactor and o_data.fillfactor != data.fillfactor %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +SET(FILLFACTOR = {{ data.fillfactor }}); + +{% elif data.fillfactor == '' %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( + FILLFACTOR +); + +{% endif %} +{# ===== Check for with_data property ===== #} +{% if data.with_data is defined and o_data.with_data|lower != data.with_data|lower %} +REFRESH MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} WITH{{ ' NO' if data.with_data|lower == 'false' else '' }} DATA; + +{% endif %} +{# ===== Check for Table tab properties ===== #} +{% if ((data.autovacuum_custom is defined and data.autovacuum_custom|lower == 'false') or +(data.toast_autovacuum is defined and data.toast_autovacuum|lower == 'false') +) %} +{% if data.autovacuum_custom is defined %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( + autovacuum_vacuum_threshold, + autovacuum_analyze_threshold, + autovacuum_vacuum_scale_factor, + autovacuum_analyze_scale_factor, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_cost_limit, + autovacuum_freeze_min_age, + autovacuum_freeze_max_age, + autovacuum_freeze_table_age +); +{% endif %} +{% if data.toast_autovacuum is defined %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} +RESET( + toast.autovacuum_vacuum_threshold, + toast.autovacuum_analyze_threshold, + toast.autovacuum_vacuum_scale_factor, + toast.autovacuum_analyze_scale_factor, + toast.autovacuum_vacuum_cost_delay, + toast.autovacuum_vacuum_cost_limit, + toast.autovacuum_freeze_min_age, + toast.autovacuum_freeze_max_age, + toast.autovacuum_freeze_table_age +); +{% endif %} +{% elif(data['vacuum_data']['changed']|length > 0) %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} SET( +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} + {{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }} +{% endif %} +{% endfor %} +); + +{% endif %}{# ===== End check for custom autovaccum ===== #} +{% endif %}{# ===== End block for check data definition ===== #} +{% if data.comment and data.comment != o_data.comment %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{# ============= The SQL generated below will change privileges ============= #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed -%} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{%- endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# ============== The SQL generated below will change Security Label ========= #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/view_id.sql new file mode 100644 index 000000000..d192a80a4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mview/ppas/9.3_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ==== #} +{% if data %} +SELECT c.oid FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/css/view.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/css/view.css new file mode 100644 index 000000000..89eae4ee0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/css/view.css @@ -0,0 +1,12 @@ +.icon-view{ + background-image: url('{{ url_for('NODE-view.static', filename='img/view.png') }}') !important; + border-radius: 10px; + background-repeat: no-repeat; + align-content: center; + vertical-align: middle; + height: 1.3em; +} + +.sql_field_height_140 { + height: 140px; +} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/js/view.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/js/view.js new file mode 100644 index 000000000..1d5e2dcd3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/js/view.js @@ -0,0 +1,267 @@ +define( + ['jquery', 'underscore', 'underscore.string', 'pgadmin', + 'pgadmin.browser', 'codemirror', 'pgadmin.browser.server.privilege', 'pgadmin.node.rule'], + +function($, _, S, pgAdmin, pgBrowser, CodeMirror) { + + /** + Create and add a view collection into nodes + @param {variable} label - Label for Node + @param {variable} type - Type of Node + @param {variable} columns - List of columns to + display under under properties. + */ + if (!pgBrowser.Nodes['coll-view']) { + var views= pgAdmin.Browser.Nodes['coll-view'] = + pgAdmin.Browser.Collection.extend({ + node: 'view', + label: '{{ _("Views") }}', + type: 'coll-view', + columns: ["name", "owner"] + }); + } + + /** + Create and Add a View Node into nodes + @param {variable} parent_type - The list of nodes + under which this node to display + @param {variable} type - Type of Node + @param {variable} hasSQL - To show SQL tab + @param {variable} canDrop - Adds drop view option + in the context menu + @param {variable} canDropCascade - Adds drop Cascade + view option in the context menu + */ + if (!pgBrowser.Nodes['view']) { + pgAdmin.Browser.Nodes['view'] = pgAdmin.Browser.Node.extend({ + parent_type: ['schema', 'catalog'], + type: 'view', + sqlAlterHelp: 'sql-alterview.html', + sqlCreateHelp: 'sql-createview.html', + label: '{{ _("View") }}', + hasSQL: true, + hasDepends: true, + collection_type: 'coll-view', + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + Init: function() { + + // Avoid mulitple registration of menus + if (this.initialized) + return; + + this.initialized = true; + + /** + Add "create view" menu option into context and object menu + for the following nodes: + coll-view, view and schema. + @property {data} - Allow create view option on schema node or + system view nodes. + */ + pgBrowser.add_menus([{ + name: 'create_view_on_coll', node: 'coll-view', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 1, label: '{{ _("View...") }}', + icon: 'wcTabIcon icon-view', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_view', node: 'view', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 1, label: '{{ _("View...") }}', + icon: 'wcTabIcon icon-view', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_view', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 17, label: '{{ _("View...") }}', + icon: 'wcTabIcon icon-view', data: {action: 'create', check: false}, + enable: 'canCreate' + } + ]); + }, + + /** + Define model for the view node and specify the + properties of the model in schema. + */ + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + var schemaLabel = args.node_info.schema.label; + this.set({'schema': schemaLabel}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'owner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + schema: [{ + id: 'name', label: '{{ _("Name") }}', cell: 'string', + type: 'text', disabled: 'inSchema' + }, + { + id: 'oid', label:'{{ _("OID") }}', cell: 'string', + type: 'text', disabled: true, mode: ['properties'] + }, + { + id: 'owner', label:'{{ _("Owner") }}', cell: 'string', control: 'node-list-by-name', + node: 'role', disabled: 'inSchema', select2: { allowClear: false } + }, + { + id: 'schema', label:'{{ _("Schema") }}', cell: 'string', first_empty: false, + control: 'node-list-by-name', type: 'text', cache_level: 'database', + node: 'schema', disabled: 'inSchema', mode: ['create', 'edit'], select2: { allowClear: false } + }, + { + id: 'system_view', label:'{{ _("System view?") }}', cell: 'string', + type: 'switch', disabled: true, mode: ['properties'] + }, + { + id: 'acl', label: '{{ _("Privileges") }}', + mode: ['properties'], type: 'text' + }, + { + id: 'comment', label:'{{ _("Comment") }}', cell: 'string', + type: 'multiline', disabled: 'inSchema' + }, + { + id: 'security_barrier', label:'{{ _("Security barrier") }}', cell: 'string', + type: 'switch', min_version: '90200', + group: 'Definition', disabled: 'inSchema' + }, + { + id: 'check_option', label:'{{ _("Check options") }}', + control: 'select2', group: 'Definition', type: 'text', + min_version: '90400', mode:['properties', 'create', 'edit'], + select2: { + + // set select2 option width to 100% + allowClear: false, + width: '100%' + }, + options:[ + {label: "No", value: "no"}, + {label: "Local", value: "local"}, + {label: "Cascaded", value: "cascaded"} + ], disabled: 'inSchema' + }, + { + id: 'definition', label:'{{ _("Definition") }}', cell: 'string', + type: 'text', mode: ['create', 'edit'], group: 'Definition', + control: Backform.SqlFieldControl, + disabled: 'inSchema' + }, + { + id: 'security', label: '{{ _("Security") }}', + type: 'group', + visible: function(m) { + if (m.top && 'catalog' in m.top.node_info) { + return false; + } + return true; + } + }, + + // Add Privilege Control + { + id: 'datacl', label: '{{ _("Privileges") }}', + model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}), uniqueCol : ['grantee'], + editable: false, type: 'collection', group: 'security', + mode: ['edit', 'create'], canAdd: true, canDelete: true, + control: 'unique-col-collection', disabled: 'inSchema' + }, + + // Add Security Labels Control + { + id: 'seclabels', label: '{{ _("Security labels") }}', + model: Backform.SecurityModel, editable: false, type: 'collection', + canEdit: false, group: 'security', canDelete: true, + mode: ['edit', 'create'], canAdd: true, disabled: 'inSchema', + control: 'unique-col-collection', uniqueCol : ['provider'] + }, + ], + validate: function() { + + // Triggers specific error messages for fields + var err = {}, + errmsg, + field_name = this.get('name'), + field_def = this.get('definition'); + if (_.isUndefined(field_name) || _.isNull(field_name) || + String(field_name).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _("Please specify name.") }}'; + errmsg = errmsg || err['name']; + this.errorModel.set('name', errmsg); + return errmsg; + }else{ + this.errorModel.unset('name'); + } + if (_.isUndefined(field_def) || _.isNull(field_def) || + String(field_def).replace(/^\s+|\s+$/g, '') == '') { + err['definition'] = '{{ _("Please enter function definition.") }}'; + errmsg = errmsg || err['definition']; + this.errorModel.set('definition', errmsg); + return errmsg; + }else{ + this.errorModel.unset('definition'); + } + return null; + }, + // We will disable everything if we are under catalog node + inSchema: function() { + if(this.node_info && 'catalog' in this.node_info) + { + return true; + } + return false; + } + }), + + /** + Show or hide create view menu option on parent node + and hide for system view in catalogs. + */ + canCreate: function(itemData, item, data) { + + // If check is false then, we will allow create menu + if (data && data.check == false) + return true; + + var t = pgBrowser.tree, i = item, d = itemData; + + // To iterate over tree to check parent node + while (i) { + + // If it is schema then allow user to create view + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-view' == d._type) { + + // Check if we are not child of view + prev_i = t.hasParent(i) ? t.parent(i) : null; + prev_d = prev_i ? t.itemData(prev_i) : null; + if( prev_d._type == 'catalog') { + return false; + } else { + return true; + } + } + i = t.hasParent(i) ? t.parent(i) : null; + d = i ? t.itemData(i) : null; + } + + // by default we do not want to allow create menu + return true; + + } + }); + } + + return pgBrowser.Nodes['coll-view']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/acl.sql new file mode 100644 index 000000000..585063903 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/acl.sql @@ -0,0 +1,51 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON ( + cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + (SELECT + (d).grantee AS grantee, + (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT + aclexplode(relacl) AS d + FROM + pg_class cl1 + WHERE + cl1.oid = {{ vid }} + ) a + ) d + ) d + LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) + LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/create.sql new file mode 100644 index 000000000..5720b1406 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/create.sql @@ -0,0 +1,20 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/properties.sql new file mode 100644 index 000000000..ce1d80185 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/properties.sql @@ -0,0 +1,69 @@ +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relname AS name, + nsp.nspname AS schema, + description AS comment, + c.reltablespace AS spcoid, + pg_get_userbyid(c.relowner) AS owner, + pg_get_viewdef(c.oid, true) AS definition, + array_to_string(c.relacl::text[], ', ') AS acl, + {#=============Checks if it is system view================#} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + (SELECT + array_agg(label) + FROM + pg_seclabels sl1 + WHERE + sl1.objoid=c.oid AND sl1.objsubid=0 + ) AS labels, + (SELECT + array_agg(provider) + FROM + pg_seclabels sl2 + WHERE sl2.objoid=c.oid AND sl2.objsubid=0 + ) AS providers +FROM pg_class c + LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace + LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace + LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +WHERE ((c.relhasrules + AND + (EXISTS( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) AND (bpchar(r.ev_type) = '1'::bpchar)) + )) + ) AND (c.relkind = 'v'::char)) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid ORDER BY c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/update.sql new file mode 100644 index 000000000..f6172a260 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/update.sql @@ -0,0 +1,67 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + AS{{ def }}; +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.1_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/acl.sql new file mode 100644 index 000000000..5f2d0fbfd --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/acl.sql @@ -0,0 +1,52 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON ( + cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + (SELECT + (d).grantee AS grantee, + (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT + aclexplode(relacl) AS d + FROM + pg_class cl1 + WHERE + cl1.oid = {{ vid }} + ) a + ) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/create.sql new file mode 100644 index 000000000..8d5f729f4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/create.sql @@ -0,0 +1,24 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }}{% if (data.security_barrier) %}{{'\r'}} +WITH ( +{% if data.security_barrier %} security_barrier={{ data.security_barrier|lower }}{% endif %}{{'\r'}} +){% endif %} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} + +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/properties.sql new file mode 100644 index 000000000..a36de2613 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/properties.sql @@ -0,0 +1,71 @@ +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + description AS comment, + c.reltablespace AS spcoid, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + pg_get_userbyid(c.relowner) AS owner, + description As comment, + pg_get_viewdef(c.oid, true) AS definition, + nsp.nspname AS schema, + array_to_string(c.relacl::text[], ', ') AS acl, + {#=============Checks if it is system view================#} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar) + ) )) + ) AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid ORDER BY c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/update.sql new file mode 100644 index 000000000..062191640 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/update.sql @@ -0,0 +1,75 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.2_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/acl.sql new file mode 100644 index 000000000..84300cfe8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/acl.sql @@ -0,0 +1,38 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON ( + cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/create.sql new file mode 100644 index 000000000..d1eec0860 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/create.sql @@ -0,0 +1,23 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }}{% if (data.security_barrier) %}{{'\r'}} +WITH ( +{% if data.security_barrier %} security_barrier={{ data.security_barrier|lower }}{% endif %}{{'\r'}} +){% endif %} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/properties.sql new file mode 100644 index 000000000..0fc7a2f6c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/properties.sql @@ -0,0 +1,74 @@ +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relkind, + description AS comment, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relname AS name, + nsp.nspname AS schema, + c.reltablespace AS spcoid, + c.relispopulated AS ispopulated, + pg_get_userbyid(c.relowner) AS owner, + array_to_string(c.relacl::text[], ', ') AS acl, + pg_get_viewdef(c.oid, true) AS definition, + {# ===== Checks if it is system view ===== #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/update.sql new file mode 100644 index 000000000..062191640 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/update.sql @@ -0,0 +1,75 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.3_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/acl.sql new file mode 100644 index 000000000..7d791f5a5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/acl.sql @@ -0,0 +1,39 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON + (cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/create.sql new file mode 100644 index 000000000..b43b51984 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/create.sql @@ -0,0 +1,22 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }}{% if ((data.check_option and data.check_option.lower() != 'no') or data.security_barrier) %}{{ '\n' }}WITH ( +{% if data.check_option and data.check_option.lower() != 'no' %} check_option={{ data.check_option }}{% endif %}{{ ',\r' if data.check_option and data.check_option.lower() != 'no' and data.security_barrier }}{% if data.security_barrier %} security_barrier={{ data.security_barrier|lower }}{% endif %}{{'\r'}} +){% endif %} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner and data.m_view is undefined %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/properties.sql new file mode 100644 index 000000000..4e5a88912 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/properties.sql @@ -0,0 +1,77 @@ +{# ========================== Fetch View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relkind, + description AS comment, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relname AS name, + c.reltablespace AS spcoid, + nsp.nspname AS schema, + c.relispopulated AS ispopulated, + pg_get_userbyid(c.relowner) AS owner, + array_to_string(c.relacl::text[], ', ') AS acl, + pg_get_viewdef(c.oid, true) AS definition, + {# ===== Checks if it is system view ===== #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + substring(array_to_string(c.reloptions, ',') + FROM 'check_option=([a-z]*)') AS check_option, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/update.sql new file mode 100644 index 000000000..ba18fcb85 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/update.sql @@ -0,0 +1,81 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (check_option={{ data.check_option|default('no', 'true') if data.check_option else o_data.check_option|default('no', 'true') }}{{', ' }}security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% if (data.check_option and data.check_option != o_data.check_option and data.check_option != 'no') %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (check_option={{ data.check_option }}); +{% elif (data.check_option and data.check_option != o_data.check_option and data.check_option == 'no') %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} RESET (check_option); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/pg/9.4_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/acl.sql new file mode 100644 index 000000000..7d791f5a5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/acl.sql @@ -0,0 +1,39 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON + (cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/create.sql new file mode 100644 index 000000000..5720b1406 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/create.sql @@ -0,0 +1,20 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/properties.sql new file mode 100644 index 000000000..aa270e25b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/properties.sql @@ -0,0 +1,76 @@ +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relkind, + description AS comment, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relname AS name, + c.reltablespace AS spcoid, + nsp.nspname AS schema, + c.relispopulated AS ispopulated, + pg_get_userbyid(c.relowner) AS owner, + array_to_string(c.relacl::text[], ', ') AS acl, + pg_get_viewdef(c.oid, true) AS definition, + {# ===== Checks if it is system view ===== #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + substring(array_to_string(c.reloptions, ',') + FROM 'check_option=([a-z]*)') AS check_option, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/update.sql new file mode 100644 index 000000000..062191640 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/update.sql @@ -0,0 +1,75 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.1_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/acl.sql new file mode 100644 index 000000000..5f2d0fbfd --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/acl.sql @@ -0,0 +1,52 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON ( + cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + (SELECT + (d).grantee AS grantee, + (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT + aclexplode(relacl) AS d + FROM + pg_class cl1 + WHERE + cl1.oid = {{ vid }} + ) a + ) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/create.sql new file mode 100644 index 000000000..d1eec0860 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/create.sql @@ -0,0 +1,23 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }}{% if (data.security_barrier) %}{{'\r'}} +WITH ( +{% if data.security_barrier %} security_barrier={{ data.security_barrier|lower }}{% endif %}{{'\r'}} +){% endif %} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/properties.sql new file mode 100644 index 000000000..20eb3df41 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/properties.sql @@ -0,0 +1,70 @@ +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + pg_get_userbyid(c.relowner) AS owner, + description As comment, + pg_get_viewdef(c.oid, true) AS definition, + nsp.nspname AS schema, + array_to_string(c.relacl::text[], ', ') AS acl, + {#=============Checks if it is system view================#} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar) + ) )) + ) AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid ORDER BY c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/update.sql new file mode 100644 index 000000000..062191640 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/update.sql @@ -0,0 +1,75 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.2_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/acl.sql new file mode 100644 index 000000000..84300cfe8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/acl.sql @@ -0,0 +1,38 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON ( + cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/create.sql new file mode 100644 index 000000000..d1eec0860 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/create.sql @@ -0,0 +1,23 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }}{% if (data.security_barrier) %}{{'\r'}} +WITH ( +{% if data.security_barrier %} security_barrier={{ data.security_barrier|lower }}{% endif %}{{'\r'}} +){% endif %} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/properties.sql new file mode 100644 index 000000000..0fc7a2f6c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/properties.sql @@ -0,0 +1,74 @@ +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relkind, + description AS comment, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relname AS name, + nsp.nspname AS schema, + c.reltablespace AS spcoid, + c.relispopulated AS ispopulated, + pg_get_userbyid(c.relowner) AS owner, + array_to_string(c.relacl::text[], ', ') AS acl, + pg_get_viewdef(c.oid, true) AS definition, + {# ===== Checks if it is system view ===== #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/update.sql new file mode 100644 index 000000000..062191640 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/update.sql @@ -0,0 +1,75 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.3_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/acl.sql new file mode 100644 index 000000000..7d791f5a5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/acl.sql @@ -0,0 +1,39 @@ +{# ============================ Get ACLs ========================= #} +{% if vid %} +SELECT + 'datacl' as deftype, + COALESCE(gt.rolname, 'public') grantee, + g.rolname grantor, + array_agg(privilege_type) as privileges, + array_agg(is_grantable) as grantable +FROM + (SELECT + d.grantee, d.grantor, d.is_grantable, + CASE d.privilege_type + WHEN 'DELETE' THEN 'd' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TRIGGER' THEN 't' + WHEN 'UPDATE' THEN 'w' + WHEN 'TRUNCATE' THEN 'D' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + relacl + FROM + pg_class cl + LEFT OUTER JOIN pg_shdescription descr ON + (cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass) + WHERE + cl.oid = {{ vid }}::OID AND relkind = 'v' + ) acl, + aclexplode(relacl) d + ) d +LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid) +LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid) +GROUP BY + g.rolname, + gt.rolname +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/create.sql new file mode 100644 index 000000000..b43b51984 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/create.sql @@ -0,0 +1,22 @@ +{#============================Create new view=========================#} +{% if display_comments %} +-- View: {{ conn|qtIdent(data.schema, data.name) }} + +-- DROP VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(data.schema, data.name) }}{% if ((data.check_option and data.check_option.lower() != 'no') or data.security_barrier) %}{{ '\n' }}WITH ( +{% if data.check_option and data.check_option.lower() != 'no' %} check_option={{ data.check_option }}{% endif %}{{ ',\r' if data.check_option and data.check_option.lower() != 'no' and data.security_barrier }}{% if data.security_barrier %} security_barrier={{ data.security_barrier|lower }}{% endif %}{{'\r'}} +){% endif %} AS +{{ data.definition.rstrip(';') }}; +{% if data.owner and data.m_view is undefined %} + +ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.comment %} +COMMENT ON VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/delete.sql new file mode 100644 index 000000000..b1c173f98 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/delete.sql @@ -0,0 +1,13 @@ +{# ====================== Drop/Cascade view by name ===================== #} +{% if vid %} +SELECT + c.relname AS name, + nsp.nspname +FROM + pg_class c +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 %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/get_schema.sql new file mode 100644 index 000000000..3bdb5dcb3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/get_schema.sql @@ -0,0 +1,7 @@ +{# ===== fetch schema name against schema oid ===== #} +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/grant.sql new file mode 100644 index 000000000..b89e34de9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/grant.sql @@ -0,0 +1,6 @@ +{# ===== Grant Permissions to User Role on Views/Tables ===== #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{# ===== We will generate Security Label SQL using macro ===== #} +{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }}{{'\r'}}{% endfor %}{{'\r'}}{% endif %}{% if data.datacl %} +{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/properties.sql new file mode 100644 index 000000000..4e5a88912 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/properties.sql @@ -0,0 +1,77 @@ +{# ========================== Fetch View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relkind, + description AS comment, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname, + c.relname AS name, + c.reltablespace AS spcoid, + nsp.nspname AS schema, + c.relispopulated AS ispopulated, + pg_get_userbyid(c.relowner) AS owner, + array_to_string(c.relacl::text[], ', ') AS acl, + pg_get_viewdef(c.oid, true) AS definition, + {# ===== Checks if it is system view ===== #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} +(SELECT + array_agg(label) +FROM + pg_seclabels sl1 +WHERE + sl1.objoid=c.oid AND sl1.objsubid=0) AS labels, +(SELECT + array_agg(provider) +FROM + pg_seclabels sl2 +WHERE + sl2.objoid=c.oid AND sl2.objsubid=0) AS providers, + substring(array_to_string(c.reloptions, ',') + FROM 'check_option=([a-z]*)') AS check_option, + (substring(array_to_string(c.reloptions, ',') + FROM 'security_barrier=([a-z|0-9]*)'))::boolean AS security_barrier +FROM pg_class c +LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'v'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/update.sql new file mode 100644 index 000000000..ba18fcb85 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/update.sql @@ -0,0 +1,81 @@ +{# ============================ Update View ========================= #} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% if data %} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{% if data.name and data.name != o_data.name %} +ALTER VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} +{% if data.schema and data.schema != o_data.schema %} +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(';') %} +CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }} + WITH (check_option={{ data.check_option|default('no', 'true') if data.check_option else o_data.check_option|default('no', 'true') }}{{', ' }}security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }}) + AS + {{ def }}; +{% else %} +{% if (data.security_barrier is defined and data.security_barrier|lower != o_data.security_barrier|lower) %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (security_barrier={{ data.security_barrier|lower }}); +{% endif %} +{% if (data.check_option and data.check_option != o_data.check_option and data.check_option != 'no') %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} + SET (check_option={{ data.check_option }}); +{% elif (data.check_option and data.check_option != o_data.check_option and data.check_option == 'no') %} +ALTER VIEW {{ conn|qtIdent(view_schema, view_name) }} RESET (check_option); +{% endif %} +{% 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 }}; +{% endif %} +{# The SQL generated below will change privileges #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# The SQL generated below will change Security Label #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/view_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/view_id.sql new file mode 100644 index 000000000..73f6da55f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/view/ppas/9.4_plus/sql/view_id.sql @@ -0,0 +1,4 @@ +{# ===== Below will provide view id for last created view ===== #} +{% if data %} +SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}'; +{% endif %} diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index 4a8141173..13f6d4b90 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -1665,13 +1665,18 @@ (_.isUndefined(s.min_version) ? true : (server_info.version >= s.min_version)) && (_.isUndefined(s.max_version) ? true : - (server_info.version <= s.max_version)))); + (server_info.version <= s.max_version)))), + visible = true; + + if (s.mode && _.isObject(s.mode)) + visible = (_.indexOf(s.mode, mode) > -1); + if (visible) + visible = evalASFunc(s.visible); + groupInfo[s.id] = { label: s.label || s.id, version_compatible: ver_in_limit, - visible: !s.mode || ( - s && s.mode && _.isObject(s.mode) && - _.indexOf(s.mode, mode) != -1) && evalASFunc(s.visible) || true + visible: visible }; return; } @@ -1768,9 +1773,13 @@ // Create an array from the dictionary with proper required // structure. _.each(groups, function(val, key) { - fields.push(_.extend({ - label: key, fields: val - }, (groupInfo[key] || {version_compatible: true, visible: true}))); + fields.push( + _.extend( + _.defaults( + groupInfo[key] || {label: key}, + {version_compatible: true, visible: true} + ), {fields: val}) + ); }); } @@ -2080,8 +2089,10 @@ '', '' ].join("\n")), - events: { - "click .select_item": "onSelect", + events: function() { + return _.extend({}, Backform.InputControl.prototype.events, { + "click .select_item": "onSelect", + }); }, onSelect: function(e) { var dialog_type = this.field.get('dialog_type');