public inbox for [email protected]help / color / mirror / Atom feed
[pgAdmin4][Patch]: Functions/Procedures Module 11+ messages / 3 participants [nested] [flat]
* [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-11 09:34 Khushboo Vashi <[email protected]> 0 siblings, 1 reply; 11+ messages in thread From: Khushboo Vashi @ 2016-03-11 09:34 UTC (permalink / raw) To: pgadmin-hackers Hi, Please find attached patch for the Functions/Procedures Module. To test this patch, "Unique collection Control and Variable Control Fixes" Patch submitted by me needs to be applied first. Thanks, Khushboo -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] pgadmin4_functions.patch (226.1K, 3-pgadmin4_functions.patch) download | inline diff: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py new file mode 100644 index 0000000..d76af66 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py @@ -0,0 +1,1266 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements Functions/Procedures Node.""" + +import json +import sys +import traceback +import copy +import re +from flask import render_template, make_response, request, jsonify, \ + current_app, url_for +from flask.ext.babel import gettext +from functools import wraps +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases.schemas as schemas +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ + parse_priv_to_db +from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ + SchemaChildModule +from config import PG_DEFAULT_DRIVER +from pgadmin.browser.server_groups.servers.databases.utils import \ + parse_sec_labels_from_db, parse_variables_from_db + + +class FunctionModule(SchemaChildModule): + """ + class FunctionModule(SchemaChildModule): + + This class represents The Functions Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Functions Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Functions collection node. + + * node_inode(): + - Returns Functions node as leaf node. + + * script_load() + - Load the module script for Functions, when schema node is + initialized. + + * csssnippets() + - Returns a snippet of css. + """ + + NODE_TYPE = 'function' + COLLECTION_LABEL = gettext("Functions") + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(FunctionModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Functions collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Functions, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css + """ + snippets = [ + render_template("function/css/function.css") + ] + snippets.extend( + super(SchemaChildModule, self).csssnippets + ) + + return snippets + +blueprint = FunctionModule(__name__) + + +class FunctionView(PGChildNodeView): + """ + class FunctionView(PGChildNodeView) + + This class inherits PGChildNodeView to get the different routes for + the module. + + The class is responsible to Create, Read, Update and Delete operations for + the Functions. + + Methods: + ------- + * validate_request(f): + - Works as a decorator. + Validating request on the request of create, update and modified SQL. + + * module_js(): + - Overrides this property to define javascript for Functions node. + + * check_precondition(f): + - Works as a decorator. + - Checks database connection status. + - Attach connection object and template path. + + * list(gid, sid, did, scid): + - List the Functions. + + * nodes(gid, sid, did, scid): + - Returns all the Functions to generate Nodes in the browser. + + * properties(gid, sid, did, scid, fnid): + - Returns the Functions properties. + + * create(gid, sid, did, scid): + - Creates a new Functions object. + + * update(gid, sid, did, scid, fnid): + - Updates the Functions object. + + * delete(gid, sid, did, scid, fnid): + - Drops the Functions object. + + * sql(gid, sid, did, scid, fnid): + - Returns the SQL for the Functions object. + + * msql(gid, sid, did, scid, fnid=None): + - Returns the modified SQL. + + * dependents(gid, sid, did, scid, fnid): + - Returns the dependents for the Functions object. + + * dependencies(gid, sid, did, scid, fnid): + - Returns the dependencies for the Functions object. + + * get_languages(gid, sid, did, scid, fnid=None): + - Returns languages. + + * get_types(gid, sid, did, scid, fnid=None): + - Returns Data Types. + """ + + node_type = 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': 'fnid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'delete': [{'delete': 'delete'}], + 'children': [{'get': 'children'}], + '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'}], + 'get_types': [{'get': 'get_types'}, {'get': 'get_types'}], + 'get_languages': [{'get': 'get_languages'}, {'get': 'get_languages'}], + 'vopts': [{}, {'get': 'variable_options'}] + }) + + @property + def required_args(self): + """ + Returns Required arguments for functions node. + Where + Required Args: + name: Name of the Function + funcowner: Function Owner + pronamespace: Function Namespace + prorettypename: Function Return Type + lanname: Function Language Name + prosrc: Function Code + probin: Function Object File + """ + return [ + 'name', + 'funcowner', + 'pronamespace', + 'prorettypename', + 'lanname', + 'prosrc', + 'probin' + ] + + def validate_request(f): + """ + Works as a decorator. + Validating request on the request of create, update and modified SQL. + """ + + @wraps(f) + def wrap(self, **kwargs): + + data = {} + if request.data: + req = json.loads(request.data) + else: + req = request.args or request.form + + if 'fnid' not in kwargs: + + for arg in self.required_args: + if (arg not in req or req[arg] == '') or\ + (arg == 'probin' and req['lanname'] == 'c' + and (arg not in req or req[arg] == '')): + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter \ + (%s)." % arg + ) + ) + + try: + list_params = [] + if request.method == 'GET': + list_params = ['arguments', 'variables', 'proacl', + 'seclabels', 'acl'] + + for key in req: + if key in list_params and req[key] != '' \ + and req[key] is not None: + # Coverts string into python list as expected. + data[key] = json.loads(req[key]) + elif ( + key == 'proretset' or key == 'proisstrict' or + key == 'prosecdef' or key == 'proiswindow' or + key == 'proleakproof' + ): + data[key] = True if ( + req[key] == 'true' or req[key] is True)\ + else False if (req[key] == 'false' or + req[key] is False) else '' + else: + data[key] = req[key] + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + self.request = data + return f(self, **kwargs) + + return wrap + + def module_js(self): + """ + Load JS file (functions.js) for this module. + """ + + return make_response( + render_template( + "function/js/functions.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + Works as a decorator. + Checks the database connection status. + Attaches the connection object and template path to the class object. + """ + + @wraps(f) + def wrap(*args, **kwargs): + self = args[0] + driver = get_driver(PG_DEFAULT_DRIVER) + self.manager = driver.connection_manager(kwargs['sid']) + + # Get database connection + self.conn = self.manager.connection(did=kwargs['did']) + + self.qtIdent = driver.qtIdent + self.qtLiteral = driver.qtLiteral + + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + ver = self.manager.version + + # Set template path for sql scripts depending + # on the server version. + self.template_path = "/".join([ + self.node_type + ]) + self.sql_template_path = "/".join([ + self.template_path, + self.manager.server_type, + 'sql', + '9.5_plus' if ver >= 90500 else + '9.2_plus' if ver >= 90200 else + '9.1_plus' + ]) + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + """ + List all the Functions. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + SQL = render_template("/".join([self.sql_template_path, 'node.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): + """ + Returns all the Functions to generate the Nodes. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + res = [] + SQL = render_template("/".join([self.sql_template_path, + 'node.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-" + self.node_type, + funcowner=row['funcowner'], + language=row['lanname'] + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, fnid=None): + """ + Returns the Function properties. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + return ajax_response( + response=resp_data, + status=200 + ) + + def _format_arguments_from_db(self, data): + """ + Create Argument list of the Function. + + Args: + data: Function Data + + Returns: + Function Arguments in the following format. + [ + {'proargtypes': 'integer', 'proargmodes: 'IN', + 'proargnames': 'column1', 'proargdefaultvals': 1}, {...} + ] + Where + Arguments: + proargtypes: Argument Types (Data Type) + proargmodes: Argument Modes [IN, OUT, INOUT, VARIADIC] + proargnames: Argument Name + proargdefaultvals: Default Value of the Argument + """ + proargtypes = [ptype for ptype in data['proargtypenames'].split(",")]\ + if data['proargtypenames'] else [] + proargmodes = data['proargmodes'] if data['proargmodes'] else [] + proargnames = data['proargnames'] if data['proargnames'] else [] + proargdefaultvals = [ptype for ptype in + data['proargdefaultvals'].split(",")] \ + if data['proargdefaultvals'] else [] + proallargtypes = data['proallargtypes'] \ + if data['proallargtypes'] else [] + + proargout = [] + proargid = [] + proargmodenames = {'i': 'IN', 'o': 'OUT', 'b': 'INOUT', + 'v': 'VARIADIC', 't': 'TABLE'} + + # The proargtypes doesn't give OUT params, so we need to fetch + # those from database explicitly, below code is written for this + # purpose. + # + # proallargtypes gives all the Function's argument including OUT, + # but we have not used that column; as the data type of this + # column (i.e. oid[]) is not supported by oidvectortypes(oidvector) + # function which we have used to fetch the datatypes + # of the other parameters. + + proargmodes_fltrd = copy.deepcopy(proargmodes) + proargnames_fltrd = [] + cnt = 0 + for m in proargmodes: + if m == 'o': # Out Mode + SQL = render_template("/".join([self.sql_template_path, + 'get_out_types.sql']), + out_arg_oid=proallargtypes[cnt]) + status, out_arg_type = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=out_arg_type) + + # Insert out parameter datatype + proargtypes.insert(cnt, out_arg_type) + proargdefaultvals.insert(cnt, '') + elif m == 'v': # Variadic Mode + proargdefaultvals.insert(cnt, '') + elif m == 't': # Table Mode + proargmodes_fltrd.remove(m) + proargnames_fltrd.append(proargnames[cnt]) + + cnt += 1 + + cnt = 0 + # Map param's short form to its actual name. (ex: 'i' to 'IN') + for m in proargmodes_fltrd: + proargmodes_fltrd[cnt] = proargmodenames[m] + cnt += 1 + + # Removes Argument Names from the list if that argument is removed + # from the list + for i in proargnames_fltrd: + proargnames.remove(i) + + # Insert null value against the parameters which do not have + # default values. + if len(proargmodes_fltrd) > len(proargdefaultvals): + dif = len(proargmodes_fltrd) - len(proargdefaultvals) + while (dif > 0): + proargdefaultvals.insert(0, '') + dif = dif - 1 + + # Prepare list of Argument list dict to be displayed in the Data Grid. + params = {"arguments": map( + lambda argid, argtype, argmode, argname, argdefval: { + "argid": argid, + "argtype": argtype.strip() if argtype is not None else '', + "argmode": argmode, + "argname": argname, + "argdefval": argdefval + }, range(len(proargtypes)), proargtypes, proargmodes_fltrd, + proargnames, proargdefaultvals)} + + # Prepare string formatted Argument to be displayed in the Properties + # panel. + proargs = map(self._map_arguments, proargmodes_fltrd, proargnames, + proargtypes, proargdefaultvals) + + proargs = {"proargs": ", ".join(proargs)} + + return params, proargs + + def _map_arguments(self, argmode, argname, argtype, argdef): + """ + Returns formatted Arguments. + Args: + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + arg = '' + + if argmode: + arg += argmode + " " + if argname: + arg += argname + " " + if argtype: + arg += argtype + " " + if argdef: + arg += " DEFAULT " + argdef + + return arg + + def _format_proacl_from_db(self, proacl): + """ + Returns privileges. + Args: + proacl: Privileges Dict + """ + privileges = [] + for row in proacl: + priv = parse_priv_from_db(row) + privileges.append(priv) + + return {"acl": privileges} + + @check_precondition + def get_types(self, gid, sid, did, scid, fnid=None): + """ + Returns the Types. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + # TODO: This function should be removed once Types module + # will be completed. + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_types.sql'])) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in rset['rows']: + res.append( + {'label': row['typname'], 'value': row['typname']} + ) + + return make_json_response( + data=res, + status=200 + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def get_languages(self, gid, sid, did, scid, fnid=None): + """ + Returns the Languages list. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_languages.sql']) + ) + status, rows = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res + rows['rows'] + + return make_json_response( + data=res, + status=200 + ) + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + current_app.logger.error(traceback.print_exception( + exc_type, + exc_value, + exc_traceback, + limit=2 + ) + ) + + return internal_server_error(errormsg=str(exc_value)) + + @check_precondition + def variable_options(self, gid, sid, did, scid, fnid=None): + """ + Returns the variables. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + This function will return list of variables available for + table spaces. + """ + SQL = render_template( + "/".join([self.sql_template_path, 'variables.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=rset) + + return make_json_response( + data=rset['rows'], + status=200 + ) + + @check_precondition + @validate_request + def create(self, gid, sid, did, scid): + """ + Create a new Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + Function object in json format. + """ + + try: + # Get SQL to create Function + status, SQL = self._get_sql(gid, sid, did, scid, self.request) + if not status: + return internal_server_error(errormsg=SQL) + + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join([self.sql_template_path, + 'get_oid.sql']), + nspname=self.request['pronamespace'], + name=self.request['name']) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res['rows'][0] + + return jsonify( + node=self.blueprint.generate_browser_node( + res['oid'], + self.request['pronamespace'], + res['name'], + icon="icon-" + self.node_type, + language=res['lanname'], + funcowner=res['funcowner'] + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, fnid): + """ + Drop the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Fetch Name and Schema Name to delete the Function. + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), scid=scid, fnid=fnid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + name, func_args, nspname = res['rows'][0] + + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), + name=name, + func_args=func_args, + nspname=nspname, + 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("Function Dropped."), + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + @validate_request + def update(self, gid, sid, did, scid, fnid): + """ + Update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + + if not status: + return internal_server_error(errormsg=SQL) + + 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) + + return make_json_response( + success=1, + info="Function Updated.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, fnid=None): + """ + Returns the SQL for the Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + # Fetch the function definition. + SQL = render_template("/".join([self.sql_template_path, + 'get_definition.sql']), fnid=fnid, scid=scid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + func_def, name = res['rows'][0] + sql_header = """-- {0}: {1} + +-- DROP {0} {1}; + +""".format(self.node_type.upper(), name) + + SQL = sql_header + func_def + + return ajax_response(response=SQL) + + @check_precondition + @validate_request + def msql(self, gid, sid, did, scid, fnid=None): + """ + Returns the modified SQL. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + Returns: + SQL statements to create/update the Domain. + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + if status: + return make_json_response( + data=SQL, + status=200 + ) + else: + return SQL + + def _get_sql(self, gid, sid, did, scid, data, fnid=None): + """ + Generates the SQL statements to create/update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + data: Function data + fnid: Function Id + """ + + try: + # Get Schema Name from its OID. + if 'pronamespace' in data: + data['pronamespace'] = self._get_schema(data[ + 'pronamespace']) + if 'provolatile' in data: + vol_dict = {'v': 'VOLATILE', 's': 'STABLE', 'i': 'IMMUTABLE'} + data['provolatile'] = vol_dict[data['provolatile']] + + if fnid is not None: + # Edit Mode + + # Fetch Old Data from database. + old_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get Schema Name + old_data['pronamespace'] = self._get_schema(old_data[ + 'pronamespace']) + + # If any of the below argument is changed, + # then CREATE OR REPLACE SQL statement should be called + fun_change_args = ['lanname', 'prosrc', 'probin', 'prosrc_c', + 'provolatile', 'proisstrict', 'prosecdef', + 'procost', 'proleakproof', 'arguments'] + + data['change_func'] = False + for arg in fun_change_args: + if arg == 'arguments' and arg in data and len(data[arg]) \ + > 0: + data['change_func'] = True + elif arg in data: + data['change_func'] = True + + # If Function Definition/Arguments are changed then merge old + # Arguments with changed ones for Create/Replace Function + # SQL statement + if 'arguments' in data and len(data['arguments']) > 0: + for arg in data['arguments']['changed']: + for old_arg in old_data['arguments']: + if arg['argid'] == old_arg['argid']: + old_arg.update(arg) + break + data['arguments'] = old_data['arguments'] + elif data['change_func']: + data['arguments'] = old_data['arguments'] + + # Parse Privileges + if 'acl' in data: + for key in ['added', 'deleted', 'changed']: + if key in data['acl']: + data['acl'][key] = parse_priv_to_db( + data['acl'][key], ["X"]) + + # Parse Variables + chngd_variables = {} + data['merged_variables'] = [] + old_data['chngd_variables'] = {} + del_variables = {} + + # If Function Definition/Arguments are changed then, + # Merge old, new (added, changed, deleted) variables, + # which will be used in the CREATE or REPLACE Function sql + # statement + + if data['change_func']: + # To compare old and new variables, preparing name : + # value dict + + # Deleted Variables + if 'variables' in data and 'deleted' in data['variables']: + for v in data['variables']['deleted']: + del_variables[v['name']] = v['value'] + + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + chngd_variables[v['name']] = v['value'] + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + chngd_variables[v['name']] = v['value'] + + for v in old_data['variables']: + old_data['chngd_variables'][v['name']] = v['value'] + + # Prepare final dict of new and old variables + for name, val in old_data['chngd_variables'].items(): + if name not in chngd_variables and name not in \ + del_variables: + chngd_variables[name] = val + + # Prepare dict in [{'name': var_name, 'value': var_val},..] + # format + for name, val in chngd_variables.items(): + data['merged_variables'].append({'name': name, + 'value': val}) + else: + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + data['merged_variables'].append(v) + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + data['merged_variables'].append(v) + + SQL = render_template( + "/".join([self.sql_template_path, 'update.sql']), + data=data, o_data=old_data + ) + else: + # Parse Privileges + if 'acl' in data: + data['acl'] = parse_priv_to_db(data['acl'], ["X"]) + + args = '' + cnt = 1 + if 'arguments' in data: + for a in data['arguments']: + if (('argmode' in a and a['argmode'] != 'OUT' and + a['argmode'] is not None + ) or 'argnode' not in a): + if 'argmode' in a: + args += a['argmode'] + " " + if 'argname' in a and a['argname'] != ''\ + and a['argname'] is not None: + args += self.qtIdent( + self.conn, a['argname']) + " " + if 'argtype' in a: + args += a['argtype'] + " " + if cnt < len(data['arguments']): + args += ', ' + cnt += 1 + + data['func_args'] = args + # Create mode + SQL = render_template("/".join([self.sql_template_path, + 'create.sql']), data=data) + return True, SQL + + except Exception as e: + return False, e + + def _fetch_properties(self, gid, sid, did, scid, fnid=None): + """ + Return Function Properties which will be used in properties, + msql function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = {} + + SQL = render_template("/".join([self.sql_template_path, + 'properties.sql']), + scid=scid, fnid=fnid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + resp_data = res['rows'][0] + + # Get formatted Arguments + frmtd_params, frmtd_proargs = self._format_arguments_from_db(resp_data) + resp_data.update(frmtd_params) + resp_data.update(frmtd_proargs) + + # Fetch privileges + SQL = render_template("/".join([self.sql_template_path, 'acl.sql']), + fnid=fnid) + status, proaclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Get Formatted Privileges + resp_data.update(self._format_proacl_from_db(proaclres['rows'])) + + # Set System Functions Status + resp_data['sysfunc'] = False + if fnid <= self.manager.db_info[did]['datlastsysoid']: + resp_data['sysfunc'] = True + + # Get formatted Security Labels + if 'seclabels' in resp_data: + resp_data.update(parse_sec_labels_from_db(resp_data['seclabels'])) + + # Get formatted Variable + resp_data.update(parse_variables_from_db([ + {"setconfig": resp_data['proconfig']}])) + + return resp_data + + def _get_schema(self, scid): + """ + Returns Schema Name from its OID. + + Args: + scid: Schema Id + """ + SQL = render_template("/".join([self.sql_template_path, + '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 dependents(self, gid, sid, did, scid, fnid): + """ + This function get the dependents and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependents_result = self.get_dependents(self.conn, fnid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, fnid): + """ + This function get the dependencies and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependencies_result = self.get_dependencies(self.conn, fnid) + return ajax_response( + response=dependencies_result, + status=200 + ) + +FunctionView.register_node_view(blueprint) + + +class ProcedureModule(SchemaChildModule): + """ + class ProcedureModule(SchemaChildModule): + + This class represents The Procedures Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Procedures Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Procedures collection node. + + * node_inode(): + - Returns Procedures node as leaf node. + + * script_load() + - Load the module script for Procedures, when schema node is + initialized. + + """ + + NODE_TYPE = 'procedure' + COLLECTION_LABEL = gettext("Procedures") + + def __init__(self, *args, **kwargs): + """ + Initialize the Procedure Module. + Args: + *args: + **kwargs: + """ + super(ProcedureModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = ['ppas'] + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Procedures collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Procedures, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + +procedure_blueprint = ProcedureModule(__name__) + + +class ProcedureView(FunctionView): + + node_type = procedure_blueprint.node_type + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(ProcedureView, self).__init__(*args, **kwargs) + + @property + def required_args(self): + """ + Returns Required arguments for procedures node. + Where + Required Args: + name: Name of the Function + pronamespace: Function Namespace + lanname: Function Language Name + prosrc: Function Code + """ + return ['name', + 'pronamespace', + 'lanname', + 'prosrc'] + + def module_js(self): + """ + Load JS file (procedures.js) for this module. + """ + + return make_response( + render_template( + "procedure/js/procedures.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + +ProcedureView.register_node_view(procedure_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png new file mode 100644 index 0000000000000000000000000000000000000000..c44874e5574e624c2687689ac75f3ba4ed69e811 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE0CVL=8;#?*`-(h^sRi9 z*>&~c)34PF?}pc0oO}FT&eYpg3!lCJ{{QpuKPl}Gawb0N+VtXry&)e^8)He3UoeBi zvm0qZ4rhT!WHFHT0Ash4*>*riqNj^vh{WaCes{hD1{^FOt?qvPzrI(~vFzEgEEaCT zKn8&fCc|T@oHyDw|30!InX~Vp=DDQ@|E}SiWNDf1d5o{vOS9^<jH6JQ%!{XA68~=T zUVHU-(WR)_zZZZ1_xt(xjh~rXW-{}Bc$;4hv`n?cHKHUXu_V<hxhNG#F&G&b8tNJt z>Kd7b7@Arcm|Gc`Y8#kY85l5Do_~m<AvZrIGp!P&!9dr*5~wG{$k@un#LB=-+W@H3 U;MDZcH9!pvp00i_>zopr06KSqcmMzZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..7c13a9bc73a782b5139095af596e15d7b68dd20c GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9EC%sCbm^nUN&dsC)d z%g%m(?%cJOmUB^2&)2TKR$To5`}b?r)x6ex&wxr9OM?7@862M7NCR>>3p^r=fwTu0 zyPeFo12PglT^vI=t|uoXgaoB9FsmgiGa57px_XMbaBFHxO0zOZW@WzA@{)3Bd#1Ev zf>nS=wRyl)0gsIDYK$8M1T>mj(wGjaEU<j_)L{XKVdhn(2@iX`tkM;(8Sb=j%x%8O z&&KdzmZ)RwGzMRwWvV5v5hW>!C8<`)MX5lF!N|bSP}jgv*T^))(A3Jn+{)NY+rZ4q zz+j);rTHita`RI%(<(t440H`FfqFuWjIB&etPFq}fI1CMO%GiI)WG2B>gTe~DWM4f DC&Fq! literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png new file mode 100644 index 0000000000000000000000000000000000000000..656854a0191b5dd5d465f90cfbceebdc3913f1a2 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF3h)VW1=3U3Jn||!yY$MRhadm{ z{r~UY=bu~de4cgqZS9ih={*lqIv$kGe$v0=Wy+ox+kmPWOM?7@862M7NCR>>3p^r= zfwTu0yPeFo12Td<T^vI=t|uorFgbMz%nH2e!Eh#_sIZa4a8(-{W2?l}DN`<8YH;#- zst}-Z;J_6|HZC3?W5<L^3=wBng(l?o+}ds4$eUzU%$C*nPL(la_XP%qilxGbk7sB! z0Zmseag8WRNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KrrHLkRt5(1-s!DE(U6;; ll9^Ts(O_T+)&Nv(Vr5_k(Qs;d=o+8~22WQ%mvv4FO#sGkaAg1h literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..8b65dff9eb2c373df031669adba7a82c0ae2aaa6 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9Cs%{mqo^m6CUA1_|~ z|NHmbqerjy?R&Ir+0E|mOJ!vji;J%}H<uLMy$n>!SQ6wH%;50sMjDXAS>O>_45U54 z*zIJt9gq>^>Eal|aXmS~fyt>$U{>Hw4~8=dMTLzVhO64x7+WQ#PMLD)QiGGvQ-uJP z0|%}!vT^bF7&|6RVu(1qDl{Rt=hklXM&2Z=Vz#WlMH3iS#bz)t#6K1K?su<o8qjpr z64!{5l*E!$tK_0oAjM#0U}&goV5n<k8e(W_WngY)Y^H5sW@TWoPwvuu6b-rgDVb@N pAPok(29`iQAx6elCMH$}Kn*~h2B)Tnt^sOb@O1TaS?83{1OQh#ZFT?v literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css new file mode 100644 index 0000000..16b2e71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css @@ -0,0 +1,3 @@ +.functions_code { + height: 130px !important; +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js new file mode 100644 index 0000000..583df21 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js @@ -0,0 +1,437 @@ +/* Create and Register Function Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.browser.collection', 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-function']) { + var functions = pgAdmin.Browser.Nodes['coll-function'] = + pgAdmin.Browser.Collection.extend({ + node: 'function', + label: '{{ _('Functions') }}', + type: 'coll-function', + columns: ['name', 'funcowner', 'description'] + }); + }; + + // Security Model + var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({ + defaults: { + provider: null, + label: null + }, + schema: [{ + id: 'provider', label: '{{ _('Provider') }}', + type: 'text' + },{ + id: 'label', label: '{{ _('Security Label') }}', + type: 'text' + }], + validate: function() { + var err = {}, + errmsg = null, + data = this.toJSON(); + + if (_.isUndefined(data.label) || + _.isNull(data.label) || + String(data.label).replace(/^\s+|\s+$/g, '') == '') { + return _("Please specify the value for all the security providers."); + } + return null; + } + }); + + // Argument Model + var ArgumentModel = pgAdmin.Browser.Node.Model.extend({ + idAttribute: 'argid', + defaults: { + argid: undefined, + argtype: undefined, + argmode: undefined, + argname: undefined, + argdefval: undefined + }, + schema: [{ + id: 'argid', visible: false, type: 'text', + mode: ['properties', 'edit','create'] + },{ + id: 'argtype', label:'{{ _('Data Type') }}', cell: + 'node-ajax-options', cellHeaderClasses: 'width_percent_30', + control: 'node-ajax-options', type: 'text', url: 'get_types', + editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argmode', label:'{{ _('Mode') }}', type: 'options', + control: 'node-ajax-options', cellHeaderClasses:'width_percent_20', + options:[ + {'label': 'IN', 'value': 'IN'}, + {'label': 'OUT', 'value': 'OUT'}, + {'label': 'INOUT', 'value': 'INOUT'}, + {'label': 'VARIADIC', 'value': 'VARIADIC'} + ], editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argname', label:'{{ _('Argument Name') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_30', + },{ + id: 'argdefval', label:'{{ _('Default Value') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_20' + } + ], + toJSON: Backbone.Model.prototype.toJSON + }); + + if (!pgBrowser.Nodes['function']) { + pgAdmin.Browser.Nodes['function'] = pgBrowser.Node.extend({ + type: 'function', + label: '{{ _('Function') }}', + collection_type: 'coll-function', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function(args) { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + pgBrowser.add_menus([{ + name: 'create_function_on_coll', node: 'coll-function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: false}, + enable: 'canCreate' + } + ]); + + }, + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + schema_id = args.node_info.schema._id + this.set({'pronamespace': schema_id}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'funcowner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + defaults: { + name: undefined, + oid: undefined, + xmin: undefined, + funcowner: undefined, + pronamespace: undefined, + description: undefined, + pronargs: undefined, /* Argument Count */ + proargs: undefined, /* Arguments */ + proargtypenames: undefined, /* Argument Signature */ + prorettypename: undefined, /* Return Type */ + lanname: 'sql', /* Language Name in which function is being written */ + provolatile: undefined, /* Volatility */ + proretset: undefined, /* Return Set */ + proisstrict: undefined, + prosecdef: undefined, /* Security of definer */ + proiswindow: undefined, /* Window Function ? */ + procost: undefined, /* Estimated execution Cost */ + prorows: undefined, /* Estimated number of rows */ + proleakproof: undefined, + arguments: [], + prosrc: undefined, + prosrc_c: undefined, + probin: '$libdir/', + options: [], + variables: [], + proacl: undefined, + seclabels: [], + acl: [], + sysfunc: undefined + }, + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'] + },{ + id: 'oid', label: '{{ _('OID') }}', cell: 'string', + type: 'text' , mode: ['properties'] + },{ + id: 'funcowner', label: '{{ _('Owner') }}', cell: 'string', + control: Backform.NodeListByNameControl, node: 'role', type: + 'text', disabled: 'isDisabled' + },{ + id: 'pronamespace', label: '{{ _('Schema') }}', cell: 'string', + control: 'node-list-by-id', type: 'text', cache_level: 'database', + node: 'schema' + },{ + id: 'description', label: '{{ _('Comment') }}', cell: 'string', + type: 'multiline' + },{ + id: 'pronargs', label: '{{ _('Argument Count') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties'] + },{ + id: 'proargs', label: '{{ _('Arguments') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties', 'edit'], + disabled: 'isDisabled' + },{ + id: 'proargtypenames', label: '{{ _('Signature Arguments') }}', cell: + 'string', type: 'text', group: '{{ _('Definition') }}', mode: ['properties'], + disabled: 'isDisabled' + },{ + id: 'prorettypename', label: '{{ _('Return Type') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_types', disabled: 'isDisabled', + mode: ['create'] + },{ + id: 'prorettypename', label: '{{ _('Return Type') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: true, + mode: ['properties', 'edit'] + }, { + id: 'lanname', label: '{{ _('Language') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_languages', disabled: 'isDisabled' + },{ + id: 'prosrc', label: '{{ _('Code') }}', cell: 'string', + type: 'multiline', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { + return false; + } + return true; + }, maxlength: '', extraClasses: ['functions_code'] + },{ + id: 'probin', label: '{{ _('Object File') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'prosrc_c', label: '{{ _('Link Symbol') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'provolatile', label: '{{ _('Volatility') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Options') }}', + options:[ + {'label': 'VOLATILE', 'value': 'v'}, + {'label': 'STABLE', 'value': 's'}, + {'label': 'IMMUTABLE', 'value': 'i'}, + ], disabled: 'isDisabled' + },{ + id: 'proretset', label: '{{ _('Returns a Set?') }}', group: '{{ _('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'proisstrict', label: '{{ _('Strict?') }}', group: '{{ _ + ('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'prosecdef', label: '{{ _('Security of definer?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'proiswindow', label: '{{ _('Window?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'procost', label: '{{ _('Estimated Cost') }}', group: '{{ _('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled' + },{ + id: 'prorows', label: '{{ _('Estimated Rows') }}', group: '{{ _ + ('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled', + deps: ['proretset'] + },{ + id: 'proleakproof', label: '{{ _('Leak proof?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', min_version: 90200, + disabled: 'isDisabled' + },{ + id: 'proacl', label: '{{ _('ACL') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'text', cell: 'string', + mode: ['properties'] + },{ + id: 'sysfunc', label: '{{ _('System Function?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + mode: ['properties'] + },{ + id: 'arguments', label: '{{ _('Parameters') }}', cell: 'string', + group: 'Parameters', type: 'collection', canAdd: function(m){ + return m.isNew(); + }, + canDelete: true, model: ArgumentModel, mode: + ['create', 'edit'], editable: false, + columns: ['argtype', 'argmode', 'argname', 'argdefval'] + },{ + id: 'variables', label: '{{ _('Variables') }}', type: 'collection', + group: '{{ _('Variables') }}', control: 'variable-collection', + model: pgAdmin.Browser.Node.VariableModel, + mode: ['edit', 'create'], canAdd: 'canVarAdd', canEdit: false, + canDelete: true, disabled: 'isDisabled' + },{ + id: 'acl', label: '{{ _('Privileges') }}', model: pgAdmin + .Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['X']}), uniqueCol : ['grantee', 'grantor'], + editable: false, type: 'collection', group: '{{ _('Previleges') }}', + mode: ['edit', 'create'], + canAdd: true, canDelete: true, control: 'unique-col-collection', + }, + { + id: 'seclabels', label: '{{ _('Security Labels') }}', + model: SecurityModel, type: 'collection', + group: '{{ _('Security') }}', mode: ['edit', 'create'], + min_version: 90100, canAdd: true, + canEdit: true, canDelete: true + } + ], + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('funcowner')) || String(this.get('funcowner')).replace(/^\s+|\s+$/g, '') == '') { + err['funcowner'] = '{{ _('Owner can not be empty!') }}'; + errmsg = errmsg || err['funcowner']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('prorettypename')) || String(this.get('prorettypename')).replace(/^\s+|\s+$/g, '') == '') { + err['prorettypename'] = '{{ _('Return Type can not be empty!') }}'; + errmsg = errmsg || err['prorettypename']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (String(this.get('lanname')) == 'c') { + if (_.isUndefined(this.get('probin')) || String(this.get('probin')) + .replace(/^\s+|\s+$/g, '') == '') { + err['probin'] = '{{ _('Object File can not be empty!') }}'; + errmsg = errmsg || err['probin']; + } + + if (_.isUndefined(this.get('prosrc_c')) || String(this.get('prosrc_c')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc_c'] = '{{ _('Link Symbol can not be empty!') }}'; + errmsg = errmsg || err['prosrc_c']; + } + } + else { + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + } + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + return null; + }, + isDisabled: function(m){ + name = this.name; + switch(name){ + case 'proargs': + case 'proargtypenames': + case 'proretset': + case 'proiswindow': + return !m.isNew(); + break; + case 'prorows': + if(m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return false; + break; + } + }, + canVarAdd: function(m) { + return true; + } + }), + 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 Function + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-function' == d._type) { + //Check if we are not child of catalog + 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['function']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql new file mode 100644 index 0000000..ea43172 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p +.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% +if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql new file mode 100644 index 0000000..5e62cd8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql new file mode 100644 index 0000000..358454b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %} {{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p + .argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql new file mode 100644 index 0000000..80a4676 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql @@ -0,0 +1,68 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p +.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% +if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql new file mode 100644 index 0000000..5e62cd8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql new file mode 100644 index 0000000..cb1f081 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql new file mode 100644 index 0000000..1d7f465 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql @@ -0,0 +1,67 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% +if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql new file mode 100644 index 0000000..5e62cd8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql new file mode 100644 index 0000000..8b28134 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..8f19af2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..c6d171b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..d38d55d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,131 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..69ae3b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.pronargs }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..c24970c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,22 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade%} CASCADE{% +endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..c6d171b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..d2a3aa8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..69ae3b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.pronargs }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..c6d171b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..3bf32da --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js new file mode 100644 index 0000000..f50ffe9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js @@ -0,0 +1,171 @@ +/* Create and Register Procedure Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.node.function', 'pgadmin.browser.collection', + 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify, Function) { + + if (!pgBrowser.Nodes['coll-procedure']) { + var procedures = pgAdmin.Browser.Nodes['coll-procedure'] = + pgAdmin.Browser.Collection.extend({ + node: 'procedure', + label: '{{ _('Procedures') }}', + type: 'coll-procedure', + columns: ['name', 'funcowner', 'description'] + }); + }; + + pgSchemaNode = pgBrowser.Nodes['schema']; + + // Inherit Functions Node + if (!pgBrowser.Nodes['procedure']) { + pgAdmin.Browser.Nodes['procedure'] = Function.extend({ + type: 'procedure', + label: '{{ _('Procedure') }}', + collection_type: 'coll-procedure', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.proc_initialized) + return; + + this.proc_initialized = true; + + pgBrowser.add_menus([{ + name: 'create_procedure_on_coll', node: 'coll-procedure', module: + this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + false} + },{ + name: 'create_procedure', node: 'procedure', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, + },{ + name: 'create_procedure', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, enable: 'canCreateProc' + } + ]); + }, + canDrop: pgSchemaNode.canChildDrop, + canDropCascade: pgSchemaNode.canChildDrop, + model: Function.model.extend({ + defaults: _.extend({}, + Function.model.prototype.defaults, + { + lanname: 'edbspl' + } + ), + canVarAdd: function(m){ + var server = this.node_info.server; + if (server.version < 90500) { + return false; + } + else { + return true; + } + }, + isDisabled: function(m) { + name = this.name; + switch(name){ + case 'provolatility': + case 'proisstrict': + case 'prosecdef': + case 'procost': + case 'proleakproof': + case 'variables': + var server = this.node_info.server; + if (server.version < 90500) { + return true; + } + else { + return false; + } + break; + case 'prorows': + var server = this.node_info.server; + if(server.version >= 90500 && m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return true; + break; + } + }, + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + return null; + }, + } + ), + canCreateProc: function(itemData, item, data) { + var node_hierarchy = this.getTreeNodeHierarchy.apply(this, [item]); + + // Do not provide Create option in catalog + if ('catalog' in node_hierarchy) + return false; + + // Procedures supported only in PPAS + if ('server' in node_hierarchy && node_hierarchy['server'].type == "ppas") + return true; + + return false; + + } + }); + + } + + return pgBrowser.Nodes['procedure']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..4acbc58 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,42 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data +.arguments %}( +{% for p in data.arguments %}{{p.argmode}}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if +data.func_args %}({{data.func_args}}) {% endif %} + + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..985e52a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,97 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} + + +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..328c371 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,41 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if +data.func_args %}({{data.func_args}}) {% endif %} + + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..985e52a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,97 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} + + +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..e09f16e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,55 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data +.arguments %}( +{% for p in data.arguments %}{{p.argmode}}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +{{ data.provolatile }}{% if data.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %}{% if data.procost %} + +COST {{data.procost|qtLiteral}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows|qtLiteral}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{{ data.prosrc }}; + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if +data.func_args %}({{data.func_args}}) {% endif %} + + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..8bf6770 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,128 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% else %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data +.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data +.prorows}} {% endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} + + +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'PROCEDURE', name, data.variables.deleted, o_data +.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'PROCEDURE', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros index 02f3307..08d9e5b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros @@ -2,12 +2,13 @@ {# Macros for Variables (functions module) #} {################################################} {% macro SET(conn, object_type, object_name, options, schema, func_args) -%} -ALTER {{object_type}} {{ conn|qtIdent(schema, object_name) }}({{func_args}}) - SET ({% for opt in options %}{% if loop.index != 1 %} -, {% endif %}{{ conn|qtIdent(opt.name) }}={{ opt.value|qtLiteral }}{% endfor %}); +ALTER {{object_type}} {{ conn|qtIdent(schema, object_name) }}({{func_args}}){% for opt in options %} + + SET {{ conn|qtIdent(opt.name) }}={{ opt.value|qtLiteral }}{% +endfor %}; {%- endmacro %} {% macro UNSET(conn, object_type, object_name, options, schema, func_args) -%} ALTER {{object_type}} {{ conn|qtIdent(schema, object_name) }}({{func_args}}) - RESET ({% for opt in options %}{% if loop.index != 1 %} -, {% endif %}{{ conn|qtIdent(opt.name) }}{% endfor %}); + RESET {% for opt in options %}{% if loop.index != 1 %} +, {% endif %}{{ conn|qtIdent(opt.name) }}{% endfor %}; {%- endmacro %} ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-11 16:47 Dave Page <[email protected]> parent: Khushboo Vashi <[email protected]> 0 siblings, 1 reply; 11+ messages in thread From: Dave Page @ 2016-03-11 16:47 UTC (permalink / raw) To: Khushboo Vashi <[email protected]>; +Cc: pgadmin-hackers Hi On Fri, Mar 11, 2016 at 9:34 AM, Khushboo Vashi <[email protected]> wrote: > Hi, > > Please find attached patch for the Functions/Procedures Module. > > To test this patch, "Unique collection Control and Variable Control Fixes" > Patch submitted by me needs to be applied first. Hi, This is looking pretty good. I did a little bit of cleanup of the SQL formatting, however I think a little more is needed; - When creating a function, we might get the following: ===== CREATE FUNCTION pem.whee(INOUT foo bigint DEFAULT 123) RETURNS bigint AS $BODY$SELECT $1;$BODY$ LANGUAGE 'sql' NOT LEAKPROOF SET backslash_quote='on'; ALTER FUNCTION pem.whee(INOUT foo bigint ) OWNER TO postgres; GRANT ALL ON FUNCTION pem.whee(INOUT foo bigint ) TO pem_user; COMMENT ON FUNCTION pem.whee(INOUT foo bigint ) IS 'whee func'; ===== - Remove the spaces after the argument lists, before the ) - Remove the double blank lines - The opening $BODY$ should be indented - LANGUAGE should be indented - The are two spaces between 'sql' and NOT. - Reverse engineered SQL may look like: ===== -- FUNCTION: pem.whee(INOUT foo bigint) -- DROP FUNCTION pem.whee(INOUT foo bigint); CREATE OR REPLACE FUNCTION pem.whee(INOUT foo bigint DEFAULT 123) RETURNS bigint LANGUAGE sql SET backslash_quote TO 'on' AS $function$SELECT $1;$function$ ===== - We should be consistent with our heredoc markers ($BODY$ vs. $function$) - There's a 1 space indent - This formatting (bar the issues above) is much nicer that the CREATE formatting. I haven't found anything else of note yet, that I haven't fixed in passing (though I have yet to test with PPAS). Updated patch attached. Thanks. -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [application/octet-stream] pgadmin4_functions-dave.patch (226.0K, 2-pgadmin4_functions-dave.patch) download | inline diff: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py new file mode 100644 index 0000000..d76af66 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py @@ -0,0 +1,1266 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements Functions/Procedures Node.""" + +import json +import sys +import traceback +import copy +import re +from flask import render_template, make_response, request, jsonify, \ + current_app, url_for +from flask.ext.babel import gettext +from functools import wraps +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases.schemas as schemas +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ + parse_priv_to_db +from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ + SchemaChildModule +from config import PG_DEFAULT_DRIVER +from pgadmin.browser.server_groups.servers.databases.utils import \ + parse_sec_labels_from_db, parse_variables_from_db + + +class FunctionModule(SchemaChildModule): + """ + class FunctionModule(SchemaChildModule): + + This class represents The Functions Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Functions Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Functions collection node. + + * node_inode(): + - Returns Functions node as leaf node. + + * script_load() + - Load the module script for Functions, when schema node is + initialized. + + * csssnippets() + - Returns a snippet of css. + """ + + NODE_TYPE = 'function' + COLLECTION_LABEL = gettext("Functions") + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(FunctionModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Functions collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Functions, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css + """ + snippets = [ + render_template("function/css/function.css") + ] + snippets.extend( + super(SchemaChildModule, self).csssnippets + ) + + return snippets + +blueprint = FunctionModule(__name__) + + +class FunctionView(PGChildNodeView): + """ + class FunctionView(PGChildNodeView) + + This class inherits PGChildNodeView to get the different routes for + the module. + + The class is responsible to Create, Read, Update and Delete operations for + the Functions. + + Methods: + ------- + * validate_request(f): + - Works as a decorator. + Validating request on the request of create, update and modified SQL. + + * module_js(): + - Overrides this property to define javascript for Functions node. + + * check_precondition(f): + - Works as a decorator. + - Checks database connection status. + - Attach connection object and template path. + + * list(gid, sid, did, scid): + - List the Functions. + + * nodes(gid, sid, did, scid): + - Returns all the Functions to generate Nodes in the browser. + + * properties(gid, sid, did, scid, fnid): + - Returns the Functions properties. + + * create(gid, sid, did, scid): + - Creates a new Functions object. + + * update(gid, sid, did, scid, fnid): + - Updates the Functions object. + + * delete(gid, sid, did, scid, fnid): + - Drops the Functions object. + + * sql(gid, sid, did, scid, fnid): + - Returns the SQL for the Functions object. + + * msql(gid, sid, did, scid, fnid=None): + - Returns the modified SQL. + + * dependents(gid, sid, did, scid, fnid): + - Returns the dependents for the Functions object. + + * dependencies(gid, sid, did, scid, fnid): + - Returns the dependencies for the Functions object. + + * get_languages(gid, sid, did, scid, fnid=None): + - Returns languages. + + * get_types(gid, sid, did, scid, fnid=None): + - Returns Data Types. + """ + + node_type = 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': 'fnid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'delete': [{'delete': 'delete'}], + 'children': [{'get': 'children'}], + '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'}], + 'get_types': [{'get': 'get_types'}, {'get': 'get_types'}], + 'get_languages': [{'get': 'get_languages'}, {'get': 'get_languages'}], + 'vopts': [{}, {'get': 'variable_options'}] + }) + + @property + def required_args(self): + """ + Returns Required arguments for functions node. + Where + Required Args: + name: Name of the Function + funcowner: Function Owner + pronamespace: Function Namespace + prorettypename: Function Return Type + lanname: Function Language Name + prosrc: Function Code + probin: Function Object File + """ + return [ + 'name', + 'funcowner', + 'pronamespace', + 'prorettypename', + 'lanname', + 'prosrc', + 'probin' + ] + + def validate_request(f): + """ + Works as a decorator. + Validating request on the request of create, update and modified SQL. + """ + + @wraps(f) + def wrap(self, **kwargs): + + data = {} + if request.data: + req = json.loads(request.data) + else: + req = request.args or request.form + + if 'fnid' not in kwargs: + + for arg in self.required_args: + if (arg not in req or req[arg] == '') or\ + (arg == 'probin' and req['lanname'] == 'c' + and (arg not in req or req[arg] == '')): + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter \ + (%s)." % arg + ) + ) + + try: + list_params = [] + if request.method == 'GET': + list_params = ['arguments', 'variables', 'proacl', + 'seclabels', 'acl'] + + for key in req: + if key in list_params and req[key] != '' \ + and req[key] is not None: + # Coverts string into python list as expected. + data[key] = json.loads(req[key]) + elif ( + key == 'proretset' or key == 'proisstrict' or + key == 'prosecdef' or key == 'proiswindow' or + key == 'proleakproof' + ): + data[key] = True if ( + req[key] == 'true' or req[key] is True)\ + else False if (req[key] == 'false' or + req[key] is False) else '' + else: + data[key] = req[key] + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + self.request = data + return f(self, **kwargs) + + return wrap + + def module_js(self): + """ + Load JS file (functions.js) for this module. + """ + + return make_response( + render_template( + "function/js/functions.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + Works as a decorator. + Checks the database connection status. + Attaches the connection object and template path to the class object. + """ + + @wraps(f) + def wrap(*args, **kwargs): + self = args[0] + driver = get_driver(PG_DEFAULT_DRIVER) + self.manager = driver.connection_manager(kwargs['sid']) + + # Get database connection + self.conn = self.manager.connection(did=kwargs['did']) + + self.qtIdent = driver.qtIdent + self.qtLiteral = driver.qtLiteral + + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + ver = self.manager.version + + # Set template path for sql scripts depending + # on the server version. + self.template_path = "/".join([ + self.node_type + ]) + self.sql_template_path = "/".join([ + self.template_path, + self.manager.server_type, + 'sql', + '9.5_plus' if ver >= 90500 else + '9.2_plus' if ver >= 90200 else + '9.1_plus' + ]) + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + """ + List all the Functions. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + SQL = render_template("/".join([self.sql_template_path, 'node.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): + """ + Returns all the Functions to generate the Nodes. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + res = [] + SQL = render_template("/".join([self.sql_template_path, + 'node.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-" + self.node_type, + funcowner=row['funcowner'], + language=row['lanname'] + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, fnid=None): + """ + Returns the Function properties. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + return ajax_response( + response=resp_data, + status=200 + ) + + def _format_arguments_from_db(self, data): + """ + Create Argument list of the Function. + + Args: + data: Function Data + + Returns: + Function Arguments in the following format. + [ + {'proargtypes': 'integer', 'proargmodes: 'IN', + 'proargnames': 'column1', 'proargdefaultvals': 1}, {...} + ] + Where + Arguments: + proargtypes: Argument Types (Data Type) + proargmodes: Argument Modes [IN, OUT, INOUT, VARIADIC] + proargnames: Argument Name + proargdefaultvals: Default Value of the Argument + """ + proargtypes = [ptype for ptype in data['proargtypenames'].split(",")]\ + if data['proargtypenames'] else [] + proargmodes = data['proargmodes'] if data['proargmodes'] else [] + proargnames = data['proargnames'] if data['proargnames'] else [] + proargdefaultvals = [ptype for ptype in + data['proargdefaultvals'].split(",")] \ + if data['proargdefaultvals'] else [] + proallargtypes = data['proallargtypes'] \ + if data['proallargtypes'] else [] + + proargout = [] + proargid = [] + proargmodenames = {'i': 'IN', 'o': 'OUT', 'b': 'INOUT', + 'v': 'VARIADIC', 't': 'TABLE'} + + # The proargtypes doesn't give OUT params, so we need to fetch + # those from database explicitly, below code is written for this + # purpose. + # + # proallargtypes gives all the Function's argument including OUT, + # but we have not used that column; as the data type of this + # column (i.e. oid[]) is not supported by oidvectortypes(oidvector) + # function which we have used to fetch the datatypes + # of the other parameters. + + proargmodes_fltrd = copy.deepcopy(proargmodes) + proargnames_fltrd = [] + cnt = 0 + for m in proargmodes: + if m == 'o': # Out Mode + SQL = render_template("/".join([self.sql_template_path, + 'get_out_types.sql']), + out_arg_oid=proallargtypes[cnt]) + status, out_arg_type = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=out_arg_type) + + # Insert out parameter datatype + proargtypes.insert(cnt, out_arg_type) + proargdefaultvals.insert(cnt, '') + elif m == 'v': # Variadic Mode + proargdefaultvals.insert(cnt, '') + elif m == 't': # Table Mode + proargmodes_fltrd.remove(m) + proargnames_fltrd.append(proargnames[cnt]) + + cnt += 1 + + cnt = 0 + # Map param's short form to its actual name. (ex: 'i' to 'IN') + for m in proargmodes_fltrd: + proargmodes_fltrd[cnt] = proargmodenames[m] + cnt += 1 + + # Removes Argument Names from the list if that argument is removed + # from the list + for i in proargnames_fltrd: + proargnames.remove(i) + + # Insert null value against the parameters which do not have + # default values. + if len(proargmodes_fltrd) > len(proargdefaultvals): + dif = len(proargmodes_fltrd) - len(proargdefaultvals) + while (dif > 0): + proargdefaultvals.insert(0, '') + dif = dif - 1 + + # Prepare list of Argument list dict to be displayed in the Data Grid. + params = {"arguments": map( + lambda argid, argtype, argmode, argname, argdefval: { + "argid": argid, + "argtype": argtype.strip() if argtype is not None else '', + "argmode": argmode, + "argname": argname, + "argdefval": argdefval + }, range(len(proargtypes)), proargtypes, proargmodes_fltrd, + proargnames, proargdefaultvals)} + + # Prepare string formatted Argument to be displayed in the Properties + # panel. + proargs = map(self._map_arguments, proargmodes_fltrd, proargnames, + proargtypes, proargdefaultvals) + + proargs = {"proargs": ", ".join(proargs)} + + return params, proargs + + def _map_arguments(self, argmode, argname, argtype, argdef): + """ + Returns formatted Arguments. + Args: + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + arg = '' + + if argmode: + arg += argmode + " " + if argname: + arg += argname + " " + if argtype: + arg += argtype + " " + if argdef: + arg += " DEFAULT " + argdef + + return arg + + def _format_proacl_from_db(self, proacl): + """ + Returns privileges. + Args: + proacl: Privileges Dict + """ + privileges = [] + for row in proacl: + priv = parse_priv_from_db(row) + privileges.append(priv) + + return {"acl": privileges} + + @check_precondition + def get_types(self, gid, sid, did, scid, fnid=None): + """ + Returns the Types. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + # TODO: This function should be removed once Types module + # will be completed. + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_types.sql'])) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in rset['rows']: + res.append( + {'label': row['typname'], 'value': row['typname']} + ) + + return make_json_response( + data=res, + status=200 + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def get_languages(self, gid, sid, did, scid, fnid=None): + """ + Returns the Languages list. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_languages.sql']) + ) + status, rows = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res + rows['rows'] + + return make_json_response( + data=res, + status=200 + ) + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + current_app.logger.error(traceback.print_exception( + exc_type, + exc_value, + exc_traceback, + limit=2 + ) + ) + + return internal_server_error(errormsg=str(exc_value)) + + @check_precondition + def variable_options(self, gid, sid, did, scid, fnid=None): + """ + Returns the variables. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + This function will return list of variables available for + table spaces. + """ + SQL = render_template( + "/".join([self.sql_template_path, 'variables.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=rset) + + return make_json_response( + data=rset['rows'], + status=200 + ) + + @check_precondition + @validate_request + def create(self, gid, sid, did, scid): + """ + Create a new Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + Function object in json format. + """ + + try: + # Get SQL to create Function + status, SQL = self._get_sql(gid, sid, did, scid, self.request) + if not status: + return internal_server_error(errormsg=SQL) + + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join([self.sql_template_path, + 'get_oid.sql']), + nspname=self.request['pronamespace'], + name=self.request['name']) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res['rows'][0] + + return jsonify( + node=self.blueprint.generate_browser_node( + res['oid'], + self.request['pronamespace'], + res['name'], + icon="icon-" + self.node_type, + language=res['lanname'], + funcowner=res['funcowner'] + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, fnid): + """ + Drop the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Fetch Name and Schema Name to delete the Function. + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), scid=scid, fnid=fnid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + name, func_args, nspname = res['rows'][0] + + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), + name=name, + func_args=func_args, + nspname=nspname, + 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("Function Dropped."), + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + @validate_request + def update(self, gid, sid, did, scid, fnid): + """ + Update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + + if not status: + return internal_server_error(errormsg=SQL) + + 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) + + return make_json_response( + success=1, + info="Function Updated.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, fnid=None): + """ + Returns the SQL for the Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + # Fetch the function definition. + SQL = render_template("/".join([self.sql_template_path, + 'get_definition.sql']), fnid=fnid, scid=scid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + func_def, name = res['rows'][0] + sql_header = """-- {0}: {1} + +-- DROP {0} {1}; + +""".format(self.node_type.upper(), name) + + SQL = sql_header + func_def + + return ajax_response(response=SQL) + + @check_precondition + @validate_request + def msql(self, gid, sid, did, scid, fnid=None): + """ + Returns the modified SQL. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + Returns: + SQL statements to create/update the Domain. + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + if status: + return make_json_response( + data=SQL, + status=200 + ) + else: + return SQL + + def _get_sql(self, gid, sid, did, scid, data, fnid=None): + """ + Generates the SQL statements to create/update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + data: Function data + fnid: Function Id + """ + + try: + # Get Schema Name from its OID. + if 'pronamespace' in data: + data['pronamespace'] = self._get_schema(data[ + 'pronamespace']) + if 'provolatile' in data: + vol_dict = {'v': 'VOLATILE', 's': 'STABLE', 'i': 'IMMUTABLE'} + data['provolatile'] = vol_dict[data['provolatile']] + + if fnid is not None: + # Edit Mode + + # Fetch Old Data from database. + old_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get Schema Name + old_data['pronamespace'] = self._get_schema(old_data[ + 'pronamespace']) + + # If any of the below argument is changed, + # then CREATE OR REPLACE SQL statement should be called + fun_change_args = ['lanname', 'prosrc', 'probin', 'prosrc_c', + 'provolatile', 'proisstrict', 'prosecdef', + 'procost', 'proleakproof', 'arguments'] + + data['change_func'] = False + for arg in fun_change_args: + if arg == 'arguments' and arg in data and len(data[arg]) \ + > 0: + data['change_func'] = True + elif arg in data: + data['change_func'] = True + + # If Function Definition/Arguments are changed then merge old + # Arguments with changed ones for Create/Replace Function + # SQL statement + if 'arguments' in data and len(data['arguments']) > 0: + for arg in data['arguments']['changed']: + for old_arg in old_data['arguments']: + if arg['argid'] == old_arg['argid']: + old_arg.update(arg) + break + data['arguments'] = old_data['arguments'] + elif data['change_func']: + data['arguments'] = old_data['arguments'] + + # Parse Privileges + if 'acl' in data: + for key in ['added', 'deleted', 'changed']: + if key in data['acl']: + data['acl'][key] = parse_priv_to_db( + data['acl'][key], ["X"]) + + # Parse Variables + chngd_variables = {} + data['merged_variables'] = [] + old_data['chngd_variables'] = {} + del_variables = {} + + # If Function Definition/Arguments are changed then, + # Merge old, new (added, changed, deleted) variables, + # which will be used in the CREATE or REPLACE Function sql + # statement + + if data['change_func']: + # To compare old and new variables, preparing name : + # value dict + + # Deleted Variables + if 'variables' in data and 'deleted' in data['variables']: + for v in data['variables']['deleted']: + del_variables[v['name']] = v['value'] + + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + chngd_variables[v['name']] = v['value'] + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + chngd_variables[v['name']] = v['value'] + + for v in old_data['variables']: + old_data['chngd_variables'][v['name']] = v['value'] + + # Prepare final dict of new and old variables + for name, val in old_data['chngd_variables'].items(): + if name not in chngd_variables and name not in \ + del_variables: + chngd_variables[name] = val + + # Prepare dict in [{'name': var_name, 'value': var_val},..] + # format + for name, val in chngd_variables.items(): + data['merged_variables'].append({'name': name, + 'value': val}) + else: + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + data['merged_variables'].append(v) + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + data['merged_variables'].append(v) + + SQL = render_template( + "/".join([self.sql_template_path, 'update.sql']), + data=data, o_data=old_data + ) + else: + # Parse Privileges + if 'acl' in data: + data['acl'] = parse_priv_to_db(data['acl'], ["X"]) + + args = '' + cnt = 1 + if 'arguments' in data: + for a in data['arguments']: + if (('argmode' in a and a['argmode'] != 'OUT' and + a['argmode'] is not None + ) or 'argnode' not in a): + if 'argmode' in a: + args += a['argmode'] + " " + if 'argname' in a and a['argname'] != ''\ + and a['argname'] is not None: + args += self.qtIdent( + self.conn, a['argname']) + " " + if 'argtype' in a: + args += a['argtype'] + " " + if cnt < len(data['arguments']): + args += ', ' + cnt += 1 + + data['func_args'] = args + # Create mode + SQL = render_template("/".join([self.sql_template_path, + 'create.sql']), data=data) + return True, SQL + + except Exception as e: + return False, e + + def _fetch_properties(self, gid, sid, did, scid, fnid=None): + """ + Return Function Properties which will be used in properties, + msql function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = {} + + SQL = render_template("/".join([self.sql_template_path, + 'properties.sql']), + scid=scid, fnid=fnid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + resp_data = res['rows'][0] + + # Get formatted Arguments + frmtd_params, frmtd_proargs = self._format_arguments_from_db(resp_data) + resp_data.update(frmtd_params) + resp_data.update(frmtd_proargs) + + # Fetch privileges + SQL = render_template("/".join([self.sql_template_path, 'acl.sql']), + fnid=fnid) + status, proaclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Get Formatted Privileges + resp_data.update(self._format_proacl_from_db(proaclres['rows'])) + + # Set System Functions Status + resp_data['sysfunc'] = False + if fnid <= self.manager.db_info[did]['datlastsysoid']: + resp_data['sysfunc'] = True + + # Get formatted Security Labels + if 'seclabels' in resp_data: + resp_data.update(parse_sec_labels_from_db(resp_data['seclabels'])) + + # Get formatted Variable + resp_data.update(parse_variables_from_db([ + {"setconfig": resp_data['proconfig']}])) + + return resp_data + + def _get_schema(self, scid): + """ + Returns Schema Name from its OID. + + Args: + scid: Schema Id + """ + SQL = render_template("/".join([self.sql_template_path, + '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 dependents(self, gid, sid, did, scid, fnid): + """ + This function get the dependents and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependents_result = self.get_dependents(self.conn, fnid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, fnid): + """ + This function get the dependencies and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependencies_result = self.get_dependencies(self.conn, fnid) + return ajax_response( + response=dependencies_result, + status=200 + ) + +FunctionView.register_node_view(blueprint) + + +class ProcedureModule(SchemaChildModule): + """ + class ProcedureModule(SchemaChildModule): + + This class represents The Procedures Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Procedures Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Procedures collection node. + + * node_inode(): + - Returns Procedures node as leaf node. + + * script_load() + - Load the module script for Procedures, when schema node is + initialized. + + """ + + NODE_TYPE = 'procedure' + COLLECTION_LABEL = gettext("Procedures") + + def __init__(self, *args, **kwargs): + """ + Initialize the Procedure Module. + Args: + *args: + **kwargs: + """ + super(ProcedureModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = ['ppas'] + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Procedures collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Procedures, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + +procedure_blueprint = ProcedureModule(__name__) + + +class ProcedureView(FunctionView): + + node_type = procedure_blueprint.node_type + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(ProcedureView, self).__init__(*args, **kwargs) + + @property + def required_args(self): + """ + Returns Required arguments for procedures node. + Where + Required Args: + name: Name of the Function + pronamespace: Function Namespace + lanname: Function Language Name + prosrc: Function Code + """ + return ['name', + 'pronamespace', + 'lanname', + 'prosrc'] + + def module_js(self): + """ + Load JS file (procedures.js) for this module. + """ + + return make_response( + render_template( + "procedure/js/procedures.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + +ProcedureView.register_node_view(procedure_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png new file mode 100644 index 0000000000000000000000000000000000000000..c44874e5574e624c2687689ac75f3ba4ed69e811 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE0CVL=8;#?*`-(h^sRi9 z*>&~c)34PF?}pc0oO}FT&eYpg3!lCJ{{QpuKPl}Gawb0N+VtXry&)e^8)He3UoeBi zvm0qZ4rhT!WHFHT0Ash4*>*riqNj^vh{WaCes{hD1{^FOt?qvPzrI(~vFzEgEEaCT zKn8&fCc|T@oHyDw|30!InX~Vp=DDQ@|E}SiWNDf1d5o{vOS9^<jH6JQ%!{XA68~=T zUVHU-(WR)_zZZZ1_xt(xjh~rXW-{}Bc$;4hv`n?cHKHUXu_V<hxhNG#F&G&b8tNJt z>Kd7b7@Arcm|Gc`Y8#kY85l5Do_~m<AvZrIGp!P&!9dr*5~wG{$k@un#LB=-+W@H3 U;MDZcH9!pvp00i_>zopr06KSqcmMzZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..7c13a9bc73a782b5139095af596e15d7b68dd20c GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9EC%sCbm^nUN&dsC)d z%g%m(?%cJOmUB^2&)2TKR$To5`}b?r)x6ex&wxr9OM?7@862M7NCR>>3p^r=fwTu0 zyPeFo12PglT^vI=t|uoXgaoB9FsmgiGa57px_XMbaBFHxO0zOZW@WzA@{)3Bd#1Ev zf>nS=wRyl)0gsIDYK$8M1T>mj(wGjaEU<j_)L{XKVdhn(2@iX`tkM;(8Sb=j%x%8O z&&KdzmZ)RwGzMRwWvV5v5hW>!C8<`)MX5lF!N|bSP}jgv*T^))(A3Jn+{)NY+rZ4q zz+j);rTHita`RI%(<(t440H`FfqFuWjIB&etPFq}fI1CMO%GiI)WG2B>gTe~DWM4f DC&Fq! literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png new file mode 100644 index 0000000000000000000000000000000000000000..656854a0191b5dd5d465f90cfbceebdc3913f1a2 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF3h)VW1=3U3Jn||!yY$MRhadm{ z{r~UY=bu~de4cgqZS9ih={*lqIv$kGe$v0=Wy+ox+kmPWOM?7@862M7NCR>>3p^r= zfwTu0yPeFo12Td<T^vI=t|uorFgbMz%nH2e!Eh#_sIZa4a8(-{W2?l}DN`<8YH;#- zst}-Z;J_6|HZC3?W5<L^3=wBng(l?o+}ds4$eUzU%$C*nPL(la_XP%qilxGbk7sB! z0Zmseag8WRNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KrrHLkRt5(1-s!DE(U6;; ll9^Ts(O_T+)&Nv(Vr5_k(Qs;d=o+8~22WQ%mvv4FO#sGkaAg1h literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..8b65dff9eb2c373df031669adba7a82c0ae2aaa6 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9Cs%{mqo^m6CUA1_|~ z|NHmbqerjy?R&Ir+0E|mOJ!vji;J%}H<uLMy$n>!SQ6wH%;50sMjDXAS>O>_45U54 z*zIJt9gq>^>Eal|aXmS~fyt>$U{>Hw4~8=dMTLzVhO64x7+WQ#PMLD)QiGGvQ-uJP z0|%}!vT^bF7&|6RVu(1qDl{Rt=hklXM&2Z=Vz#WlMH3iS#bz)t#6K1K?su<o8qjpr z64!{5l*E!$tK_0oAjM#0U}&goV5n<k8e(W_WngY)Y^H5sW@TWoPwvuu6b-rgDVb@N pAPok(29`iQAx6elCMH$}Kn*~h2B)Tnt^sOb@O1TaS?83{1OQh#ZFT?v literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css new file mode 100644 index 0000000..16b2e71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css @@ -0,0 +1,3 @@ +.functions_code { + height: 130px !important; +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js new file mode 100644 index 0000000..7ecec15 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js @@ -0,0 +1,437 @@ +/* Create and Register Function Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.browser.collection', 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-function']) { + var functions = pgAdmin.Browser.Nodes['coll-function'] = + pgAdmin.Browser.Collection.extend({ + node: 'function', + label: '{{ _('Functions') }}', + type: 'coll-function', + columns: ['name', 'funcowner', 'description'] + }); + }; + + // Security Model + var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({ + defaults: { + provider: null, + label: null + }, + schema: [{ + id: 'provider', label: '{{ _('Provider') }}', + type: 'text' + },{ + id: 'label', label: '{{ _('Security Label') }}', + type: 'text' + }], + validate: function() { + var err = {}, + errmsg = null, + data = this.toJSON(); + + if (_.isUndefined(data.label) || + _.isNull(data.label) || + String(data.label).replace(/^\s+|\s+$/g, '') == '') { + return _("Please specify the value for all the security providers."); + } + return null; + } + }); + + // Argument Model + var ArgumentModel = pgAdmin.Browser.Node.Model.extend({ + idAttribute: 'argid', + defaults: { + argid: undefined, + argtype: undefined, + argmode: undefined, + argname: undefined, + argdefval: undefined + }, + schema: [{ + id: 'argid', visible: false, type: 'text', + mode: ['properties', 'edit','create'] + },{ + id: 'argtype', label:'{{ _('Data Type') }}', cell: + 'node-ajax-options', cellHeaderClasses: 'width_percent_30', + control: 'node-ajax-options', type: 'text', url: 'get_types', + editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argmode', label:'{{ _('Mode') }}', type: 'options', + control: 'node-ajax-options', cellHeaderClasses:'width_percent_20', + options:[ + {'label': 'IN', 'value': 'IN'}, + {'label': 'OUT', 'value': 'OUT'}, + {'label': 'INOUT', 'value': 'INOUT'}, + {'label': 'VARIADIC', 'value': 'VARIADIC'} + ], editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argname', label:'{{ _('Argument Name') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_30', + },{ + id: 'argdefval', label:'{{ _('Default Value') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_20' + } + ], + toJSON: Backbone.Model.prototype.toJSON + }); + + if (!pgBrowser.Nodes['function']) { + pgAdmin.Browser.Nodes['function'] = pgBrowser.Node.extend({ + type: 'function', + label: '{{ _('Function') }}', + collection_type: 'coll-function', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function(args) { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + pgBrowser.add_menus([{ + name: 'create_function_on_coll', node: 'coll-function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: false}, + enable: 'canCreate' + } + ]); + + }, + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + schema_id = args.node_info.schema._id + this.set({'pronamespace': schema_id}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'funcowner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + defaults: { + name: undefined, + oid: undefined, + xmin: undefined, + funcowner: undefined, + pronamespace: undefined, + description: undefined, + pronargs: undefined, /* Argument Count */ + proargs: undefined, /* Arguments */ + proargtypenames: undefined, /* Argument Signature */ + prorettypename: undefined, /* Return Type */ + lanname: 'sql', /* Language Name in which function is being written */ + provolatile: undefined, /* Volatility */ + proretset: undefined, /* Return Set */ + proisstrict: undefined, + prosecdef: undefined, /* Security of definer */ + proiswindow: undefined, /* Window Function ? */ + procost: undefined, /* Estimated execution Cost */ + prorows: undefined, /* Estimated number of rows */ + proleakproof: undefined, + arguments: [], + prosrc: undefined, + prosrc_c: undefined, + probin: '$libdir/', + options: [], + variables: [], + proacl: undefined, + seclabels: [], + acl: [], + sysfunc: undefined + }, + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'] + },{ + id: 'oid', label: '{{ _('OID') }}', cell: 'string', + type: 'text' , mode: ['properties'] + },{ + id: 'funcowner', label: '{{ _('Owner') }}', cell: 'string', + control: Backform.NodeListByNameControl, node: 'role', type: + 'text', disabled: 'isDisabled' + },{ + id: 'pronamespace', label: '{{ _('Schema') }}', cell: 'string', + control: 'node-list-by-id', type: 'text', cache_level: 'database', + node: 'schema' + },{ + id: 'sysfunc', label: '{{ _('System Function?') }}', + cell:'boolean', type: 'switch', + mode: ['properties'] + },{ + id: 'description', label: '{{ _('Comment') }}', cell: 'string', + type: 'multiline' + },{ + id: 'pronargs', label: '{{ _('Argument Count') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties'] + },{ + id: 'proargs', label: '{{ _('Arguments') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties', 'edit'], + disabled: 'isDisabled' + },{ + id: 'proargtypenames', label: '{{ _('Signature Arguments') }}', cell: + 'string', type: 'text', group: '{{ _('Definition') }}', mode: ['properties'], + disabled: 'isDisabled' + },{ + id: 'prorettypename', label: '{{ _('Return Type') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_types', disabled: 'isDisabled', + mode: ['create'] + },{ + id: 'prorettypename', label: '{{ _('Return Type') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: true, + mode: ['properties', 'edit'] + }, { + id: 'lanname', label: '{{ _('Language') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_languages', disabled: 'isDisabled' + },{ + id: 'prosrc', label: '{{ _('Code') }}', cell: 'string', + type: 'multiline', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { + return false; + } + return true; + }, maxlength: '', extraClasses: ['functions_code'] + },{ + id: 'probin', label: '{{ _('Object File') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'prosrc_c', label: '{{ _('Link Symbol') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'provolatile', label: '{{ _('Volatility') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Options') }}', + options:[ + {'label': 'VOLATILE', 'value': 'v'}, + {'label': 'STABLE', 'value': 's'}, + {'label': 'IMMUTABLE', 'value': 'i'}, + ], disabled: 'isDisabled' + },{ + id: 'proretset', label: '{{ _('Returns a Set?') }}', group: '{{ _('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'proisstrict', label: '{{ _('Strict?') }}', group: '{{ _ + ('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'prosecdef', label: '{{ _('Security of definer?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'proiswindow', label: '{{ _('Window?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'procost', label: '{{ _('Estimated Cost') }}', group: '{{ _('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled' + },{ + id: 'prorows', label: '{{ _('Estimated Rows') }}', group: '{{ _ + ('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled', + deps: ['proretset'] + },{ + id: 'proleakproof', label: '{{ _('Leak proof?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', min_version: 90200, + disabled: 'isDisabled' + },{ + id: 'proacl', label: '{{ _('Privileges') }}', + group: '{{ _('Security') }}', cell:'boolean', type: 'text', cell: 'string', + mode: ['properties'] + },{ + id: 'arguments', label: '{{ _('Parameters') }}', cell: 'string', + group: 'Parameters', type: 'collection', canAdd: function(m){ + return m.isNew(); + }, + canDelete: true, model: ArgumentModel, mode: + ['create', 'edit'], editable: false, + columns: ['argtype', 'argmode', 'argname', 'argdefval'] + },{ + id: 'variables', label: '{{ _('Variables') }}', type: 'collection', + group: '{{ _('Variables') }}', control: 'variable-collection', + model: pgAdmin.Browser.Node.VariableModel, + mode: ['edit', 'create'], canAdd: 'canVarAdd', canEdit: false, + canDelete: true, disabled: 'isDisabled' + },{ + id: 'acl', label: '{{ _('Privileges') }}', model: pgAdmin + .Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['X']}), uniqueCol : ['grantee', 'grantor'], + editable: false, type: 'collection', group: '{{ _('Security') }}', + mode: ['edit', 'create'], + canAdd: true, canDelete: true, control: 'unique-col-collection', + }, + { + id: 'seclabels', label: '{{ _('Security Labels') }}', + model: SecurityModel, type: 'collection', + group: '{{ _('Security') }}', mode: ['edit', 'create'], + min_version: 90100, canAdd: true, + canEdit: true, canDelete: true + } + ], + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('funcowner')) || String(this.get('funcowner')).replace(/^\s+|\s+$/g, '') == '') { + err['funcowner'] = '{{ _('Owner can not be empty!') }}'; + errmsg = errmsg || err['funcowner']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('prorettypename')) || String(this.get('prorettypename')).replace(/^\s+|\s+$/g, '') == '') { + err['prorettypename'] = '{{ _('Return Type can not be empty!') }}'; + errmsg = errmsg || err['prorettypename']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (String(this.get('lanname')) == 'c') { + if (_.isUndefined(this.get('probin')) || String(this.get('probin')) + .replace(/^\s+|\s+$/g, '') == '') { + err['probin'] = '{{ _('Object File can not be empty!') }}'; + errmsg = errmsg || err['probin']; + } + + if (_.isUndefined(this.get('prosrc_c')) || String(this.get('prosrc_c')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc_c'] = '{{ _('Link Symbol can not be empty!') }}'; + errmsg = errmsg || err['prosrc_c']; + } + } + else { + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + } + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + return null; + }, + isDisabled: function(m){ + name = this.name; + switch(name){ + case 'proargs': + case 'proargtypenames': + case 'proretset': + case 'proiswindow': + return !m.isNew(); + break; + case 'prorows': + if(m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return false; + break; + } + }, + canVarAdd: function(m) { + return true; + } + }), + 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 Function + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-function' == d._type) { + //Check if we are not child of catalog + 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['function']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql new file mode 100644 index 0000000..ea43172 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p +.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% +if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql new file mode 100644 index 0000000..358454b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %} {{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p + .argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql new file mode 100644 index 0000000..80a4676 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql @@ -0,0 +1,68 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p +.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% +if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql new file mode 100644 index 0000000..cb1f081 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql new file mode 100644 index 0000000..1d7f465 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql @@ -0,0 +1,67 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% +if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql new file mode 100644 index 0000000..8b28134 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..8f19af2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.provolatile }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..d38d55d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,131 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..69ae3b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.pronargs }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..c24970c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,22 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade%} CASCADE{% +endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..d2a3aa8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..69ae3b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,66 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{{p.argmode}} {% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data + .prorettypename) }} AS +{% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ data.prosrc }}$BODY$ +{% endif %} +LANGUAGE {{ data.lanname|qtLiteral }} {{ data.pronargs }}{% if data +.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %} +{% if data.proiswindow %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data +.func_args}}) + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..3bf32da --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,132 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) RETURNS {{ o_data.prorettypename }} AS +{% if 'lanname' in lanname and data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% elif 'lanname' in data and 'prosrc' in data %} +$BODY${{ data.prosrc }}$BODY$ +{% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }} +{% else %} +$BODY${{ o_data.prosrc }}$BODY$ +{% endif -%} + +{% if 'lanname' in data %} +LANGUAGE {{ data.lanname|qtLiteral }}{% else %} +LANGUAGE {{ o_data.lanname|qtLiteral }}{% endif -%}{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data.prorows}} {% +endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ +o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js new file mode 100644 index 0000000..f50ffe9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js @@ -0,0 +1,171 @@ +/* Create and Register Procedure Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.node.function', 'pgadmin.browser.collection', + 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify, Function) { + + if (!pgBrowser.Nodes['coll-procedure']) { + var procedures = pgAdmin.Browser.Nodes['coll-procedure'] = + pgAdmin.Browser.Collection.extend({ + node: 'procedure', + label: '{{ _('Procedures') }}', + type: 'coll-procedure', + columns: ['name', 'funcowner', 'description'] + }); + }; + + pgSchemaNode = pgBrowser.Nodes['schema']; + + // Inherit Functions Node + if (!pgBrowser.Nodes['procedure']) { + pgAdmin.Browser.Nodes['procedure'] = Function.extend({ + type: 'procedure', + label: '{{ _('Procedure') }}', + collection_type: 'coll-procedure', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.proc_initialized) + return; + + this.proc_initialized = true; + + pgBrowser.add_menus([{ + name: 'create_procedure_on_coll', node: 'coll-procedure', module: + this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + false} + },{ + name: 'create_procedure', node: 'procedure', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, + },{ + name: 'create_procedure', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, enable: 'canCreateProc' + } + ]); + }, + canDrop: pgSchemaNode.canChildDrop, + canDropCascade: pgSchemaNode.canChildDrop, + model: Function.model.extend({ + defaults: _.extend({}, + Function.model.prototype.defaults, + { + lanname: 'edbspl' + } + ), + canVarAdd: function(m){ + var server = this.node_info.server; + if (server.version < 90500) { + return false; + } + else { + return true; + } + }, + isDisabled: function(m) { + name = this.name; + switch(name){ + case 'provolatility': + case 'proisstrict': + case 'prosecdef': + case 'procost': + case 'proleakproof': + case 'variables': + var server = this.node_info.server; + if (server.version < 90500) { + return true; + } + else { + return false; + } + break; + case 'prorows': + var server = this.node_info.server; + if(server.version >= 90500 && m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return true; + break; + } + }, + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + return null; + }, + } + ), + canCreateProc: function(itemData, item, data) { + var node_hierarchy = this.getTreeNodeHierarchy.apply(this, [item]); + + // Do not provide Create option in catalog + if ('catalog' in node_hierarchy) + return false; + + // Procedures supported only in PPAS + if ('server' in node_hierarchy && node_hierarchy['server'].type == "ppas") + return true; + + return false; + + } + }); + + } + + return pgBrowser.Nodes['procedure']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..4acbc58 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,42 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data +.arguments %}( +{% for p in data.arguments %}{{p.argmode}}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if +data.func_args %}({{data.func_args}}) {% endif %} + + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..985e52a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,97 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} + + +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..328c371 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,41 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if +data.func_args %}({{data.func_args}}) {% endif %} + + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..985e52a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,97 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} + + +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..e09f16e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,55 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data +.arguments %}( +{% for p in data.arguments %}{{p.argmode}}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +{{ data.provolatile }}{% if data.proleakproof %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if data.proisstrict %} STRICT{% endif %} +{% if data.prosecdef %} SECURITY DEFINER{% endif %}{% if data.procost %} + +COST {{data.procost|qtLiteral}}{% endif %}{% if data.prorows %} + +ROWS {{data.prorows|qtLiteral}}{% endif -%}{% if data.variables %} + +{% for v in data.variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{{ data.prosrc }}; + +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p +.with_grant, data.pronamespace, data.func_args)}} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if +data.func_args %}({{data.func_args}}) {% endif %} + + IS '{{ data.description }}'; +{% endif -%} + +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data +.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..8bf6770 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,128 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}}{% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname) }}{% endif %}{% if p.argtype %} {{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% else %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}{% if data.procost %} + +COST {{data.procost}}{% elif o_data.procost %} COST {{o_data +.procost}} {% endif %}{% if data.prorows %} + +ROWS {{data.prorows}} {% elif o_data.prorows %} ROWS {{o_data +.prorows}} {% endif -%}{% if data.merged_variables %} + +{% for v in data.merged_variables %} + +SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} + + +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} + + +{# The SQL generated below will change priviledges #} +{% if data.acl %} + +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data +.pronamespace, o_data.proargtypenames) }} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} + + +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'PROCEDURE', name, data.variables.deleted, o_data +.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'PROCEDURE', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} + +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data +.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} + +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros index 02f3307..08d9e5b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/variable.macros @@ -2,12 +2,13 @@ {# Macros for Variables (functions module) #} {################################################} {% macro SET(conn, object_type, object_name, options, schema, func_args) -%} -ALTER {{object_type}} {{ conn|qtIdent(schema, object_name) }}({{func_args}}) - SET ({% for opt in options %}{% if loop.index != 1 %} -, {% endif %}{{ conn|qtIdent(opt.name) }}={{ opt.value|qtLiteral }}{% endfor %}); +ALTER {{object_type}} {{ conn|qtIdent(schema, object_name) }}({{func_args}}){% for opt in options %} + + SET {{ conn|qtIdent(opt.name) }}={{ opt.value|qtLiteral }}{% +endfor %}; {%- endmacro %} {% macro UNSET(conn, object_type, object_name, options, schema, func_args) -%} ALTER {{object_type}} {{ conn|qtIdent(schema, object_name) }}({{func_args}}) - RESET ({% for opt in options %}{% if loop.index != 1 %} -, {% endif %}{{ conn|qtIdent(opt.name) }}{% endfor %}); + RESET {% for opt in options %}{% if loop.index != 1 %} +, {% endif %}{{ conn|qtIdent(opt.name) }}{% endfor %}; {%- endmacro %} ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-22 10:51 Khushboo Vashi <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 11+ messages in thread From: Khushboo Vashi @ 2016-03-22 10:51 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi, Please find updated Patch for the Functions/Procedures Module. On Fri, Mar 11, 2016 at 10:17 PM, Dave Page <[email protected]> wrote: > Hi > > On Fri, Mar 11, 2016 at 9:34 AM, Khushboo Vashi > <[email protected]> wrote: > > Hi, > > > > Please find attached patch for the Functions/Procedures Module. > > > > To test this patch, "Unique collection Control and Variable Control > Fixes" > > Patch submitted by me needs to be applied first. > > Hi, > > This is looking pretty good. I did a little bit of cleanup of the SQL > formatting, however I think a little more is needed; > > - When creating a function, we might get the following: > > ===== > CREATE FUNCTION pem.whee(INOUT foo bigint DEFAULT 123) RETURNS bigint AS > $BODY$SELECT $1;$BODY$ > LANGUAGE 'sql' NOT LEAKPROOF > > SET backslash_quote='on'; > > > ALTER FUNCTION pem.whee(INOUT foo bigint ) > OWNER TO postgres; > > GRANT ALL ON FUNCTION pem.whee(INOUT foo bigint ) TO pem_user; > > > COMMENT ON FUNCTION pem.whee(INOUT foo bigint ) > IS 'whee func'; > ===== > > - Remove the spaces after the argument lists, before the ) > Done > - Remove the double blank lines > Done > - The opening $BODY$ should be indented > Done and also replaced it with $function > - LANGUAGE should be indented > Done > - The are two spaces between 'sql' and NOT. > I have put function options into the next line as Reverse engineered SQL > > - Reverse engineered SQL may look like: > > ===== > -- FUNCTION: pem.whee(INOUT foo bigint) > > -- DROP FUNCTION pem.whee(INOUT foo bigint); > > CREATE OR REPLACE FUNCTION pem.whee(INOUT foo bigint DEFAULT 123) > RETURNS bigint > LANGUAGE sql > SET backslash_quote TO 'on' > AS $function$SELECT $1;$function$ > ===== > > - We should be consistent with our heredoc markers ($BODY$ vs. > $function$) > Replaced $BODY with $function > - There's a 1 space indent > As per our discussion, will not fix this 1 space indent because the Function definition SQL is coming from pg_def_functiondef function > - This formatting (bar the issues above) is much nicer that the > CREATE formatting. > > I haven't found anything else of note yet, that I haven't fixed in > passing (though I have yet to test with PPAS). Updated patch attached. > > Thanks. > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] pgAdmin4_function_ver1.patch (229.7K, 3-pgAdmin4_function_ver1.patch) download | inline diff: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py new file mode 100644 index 0000000..25bb07e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py @@ -0,0 +1,1295 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements Functions/Procedures Node.""" + +import json +import sys +import traceback +import copy +import re +from flask import render_template, make_response, request, jsonify, \ + current_app, url_for +from flask.ext.babel import gettext +from functools import wraps +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases.schemas as schemas +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ + parse_priv_to_db +from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ + SchemaChildModule, DataTypeReader +from config import PG_DEFAULT_DRIVER +from pgadmin.browser.server_groups.servers.databases.utils import \ + parse_sec_labels_from_db, parse_variables_from_db + +class FunctionModule(SchemaChildModule): + """ + class FunctionModule(SchemaChildModule): + + This class represents The Functions Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Functions Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Functions collection node. + + * node_inode(): + - Returns Functions node as leaf node. + + * script_load() + - Load the module script for Functions, when schema node is + initialized. + + * csssnippets() + - Returns a snippet of css. + """ + + NODE_TYPE = 'function' + COLLECTION_LABEL = gettext("Functions") + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(FunctionModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Functions collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Functions, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css + """ + snippets = [ + render_template("function/css/function.css") + ] + snippets.extend( + super(SchemaChildModule, self).csssnippets + ) + + return snippets + +blueprint = FunctionModule(__name__) + + +class FunctionView(PGChildNodeView, DataTypeReader): + """ + class FunctionView(PGChildNodeView) + + This class inherits PGChildNodeView to get the different routes for + the module. + + The class is responsible to Create, Read, Update and Delete operations for + the Functions. + + Methods: + ------- + * validate_request(f): + - Works as a decorator. + Validating request on the request of create, update and modified SQL. + + * module_js(): + - Overrides this property to define javascript for Functions node. + + * check_precondition(f): + - Works as a decorator. + - Checks database connection status. + - Attach connection object and template path. + + * list(gid, sid, did, scid): + - List the Functions. + + * nodes(gid, sid, did, scid): + - Returns all the Functions to generate Nodes in the browser. + + * properties(gid, sid, did, scid, fnid): + - Returns the Functions properties. + + * create(gid, sid, did, scid): + - Creates a new Functions object. + + * update(gid, sid, did, scid, fnid): + - Updates the Functions object. + + * delete(gid, sid, did, scid, fnid): + - Drops the Functions object. + + * sql(gid, sid, did, scid, fnid): + - Returns the SQL for the Functions object. + + * msql(gid, sid, did, scid, fnid=None): + - Returns the modified SQL. + + * dependents(gid, sid, did, scid, fnid): + - Returns the dependents for the Functions object. + + * dependencies(gid, sid, did, scid, fnid): + - Returns the dependencies for the Functions object. + + * get_languages(gid, sid, did, scid, fnid=None): + - Returns languages. + + * types(gid, sid, did, scid, fnid=None): + - Returns Data Types. + """ + + node_type = 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': 'fnid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'delete': [{'delete': 'delete'}], + 'children': [{'get': 'children'}], + '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'}], + 'get_types': [{'get': 'types'}, {'get': 'types'}], + 'get_languages': [{'get': 'get_languages'}, {'get': 'get_languages'}], + 'vopts': [{}, {'get': 'variable_options'}] + }) + + @property + def required_args(self): + """ + Returns Required arguments for functions node. + Where + Required Args: + name: Name of the Function + funcowner: Function Owner + pronamespace: Function Namespace + prorettypename: Function Return Type + lanname: Function Language Name + prosrc: Function Code + probin: Function Object File + """ + return [ + 'name', + 'funcowner', + 'pronamespace', + 'prorettypename', + 'lanname', + 'prosrc', + 'probin' + ] + + def validate_request(f): + """ + Works as a decorator. + Validating request on the request of create, update and modified SQL. + """ + + @wraps(f) + def wrap(self, **kwargs): + + data = {} + if request.data: + req = json.loads(request.data.decode()) + else: + req = request.args or request.form + + if 'fnid' not in kwargs: + + for arg in self.required_args: + if (arg not in req or req[arg] == '') or\ + (arg == 'probin' and req['lanname'] == 'c' + and (arg not in req or req[arg] == '')): + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter \ + (%s)." % arg + ) + ) + + try: + list_params = [] + if request.method == 'GET': + list_params = ['arguments', 'variables', 'proacl', + 'seclabels', 'acl'] + + for key in req: + if key in list_params and req[key] != '' \ + and req[key] is not None: + # Coverts string into python list as expected. + data[key] = json.loads(req[key]) + elif ( + key == 'proretset' or key == 'proisstrict' or + key == 'prosecdef' or key == 'proiswindow' or + key == 'proleakproof' + ): + data[key] = True if ( + req[key] == 'true' or req[key] is True)\ + else False if (req[key] == 'false' or + req[key] is False) else '' + else: + data[key] = req[key] + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + self.request = data + return f(self, **kwargs) + + return wrap + + def module_js(self): + """ + Load JS file (functions.js) for this module. + """ + + return make_response( + render_template( + "function/js/functions.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + Works as a decorator. + Checks the database connection status. + Attaches the connection object and template path to the class object. + """ + + @wraps(f) + def wrap(*args, **kwargs): + self = args[0] + driver = get_driver(PG_DEFAULT_DRIVER) + self.manager = driver.connection_manager(kwargs['sid']) + + # Get database connection + self.conn = self.manager.connection(did=kwargs['did']) + + self.qtIdent = driver.qtIdent + self.qtLiteral = driver.qtLiteral + + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + ver = self.manager.version + + # Set template path for sql scripts depending + # on the server version. + self.template_path = "/".join([ + self.node_type + ]) + self.sql_template_path = "/".join([ + self.template_path, + self.manager.server_type, + 'sql', + '9.5_plus' if ver >= 90500 else + '9.2_plus' if ver >= 90200 else + '9.1_plus' + ]) + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + """ + List all the Functions. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + SQL = render_template("/".join([self.sql_template_path, 'node.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): + """ + Returns all the Functions to generate the Nodes. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + res = [] + SQL = render_template("/".join([self.sql_template_path, + 'node.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-" + self.node_type, + funcowner=row['funcowner'], + language=row['lanname'] + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, fnid=None): + """ + Returns the Function properties. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + return ajax_response( + response=resp_data, + status=200 + ) + + def _format_arguments_from_db(self, data): + """ + Create Argument list of the Function. + + Args: + data: Function Data + + Returns: + Function Arguments in the following format. + [ + {'proargtypes': 'integer', 'proargmodes: 'IN', + 'proargnames': 'column1', 'proargdefaultvals': 1}, {...} + ] + Where + Arguments: + proargtypes: Argument Types (Data Type) + proargmodes: Argument Modes [IN, OUT, INOUT, VARIADIC] + proargnames: Argument Name + proargdefaultvals: Default Value of the Argument + """ + proargtypes = [ptype for ptype in data['proargtypenames'].split(",")]\ + if data['proargtypenames'] else [] + proargmodes = data['proargmodes'] if data['proargmodes'] else [] + proargnames = data['proargnames'] if data['proargnames'] else [] + proargdefaultvals = [ptype for ptype in + data['proargdefaultvals'].split(",")] \ + if data['proargdefaultvals'] else [] + proallargtypes = data['proallargtypes'] \ + if data['proallargtypes'] else [] + + proargout = [] + proargid = [] + proargmodenames = {'i': 'IN', 'o': 'OUT', 'b': 'INOUT', + 'v': 'VARIADIC', 't': 'TABLE'} + + # The proargtypes doesn't give OUT params, so we need to fetch + # those from database explicitly, below code is written for this + # purpose. + # + # proallargtypes gives all the Function's argument including OUT, + # but we have not used that column; as the data type of this + # column (i.e. oid[]) is not supported by oidvectortypes(oidvector) + # function which we have used to fetch the datatypes + # of the other parameters. + + proargmodes_fltrd = copy.deepcopy(proargmodes) + proargnames_fltrd = [] + cnt = 0 + for m in proargmodes: + if m == 'o': # Out Mode + SQL = render_template("/".join([self.sql_template_path, + 'get_out_types.sql']), + out_arg_oid=proallargtypes[cnt]) + status, out_arg_type = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=out_arg_type) + + # Insert out parameter datatype + proargtypes.insert(cnt, out_arg_type) + proargdefaultvals.insert(cnt, '') + elif m == 'v': # Variadic Mode + proargdefaultvals.insert(cnt, '') + elif m == 't': # Table Mode + proargmodes_fltrd.remove(m) + proargnames_fltrd.append(proargnames[cnt]) + + cnt += 1 + + cnt = 0 + # Map param's short form to its actual name. (ex: 'i' to 'IN') + for m in proargmodes_fltrd: + proargmodes_fltrd[cnt] = proargmodenames[m] + cnt += 1 + + # Removes Argument Names from the list if that argument is removed + # from the list + for i in proargnames_fltrd: + proargnames.remove(i) + + # Insert null value against the parameters which do not have + # default values. + if len(proargmodes_fltrd) > len(proargdefaultvals): + dif = len(proargmodes_fltrd) - len(proargdefaultvals) + while (dif > 0): + proargdefaultvals.insert(0, '') + dif = dif - 1 + + # Prepare list of Argument list dict to be displayed in the Data Grid. + params = {"arguments": [ + self._map_arguments_dict( + i, proargmodes_fltrd[i] if len(proargmodes_fltrd) > i else '', + proargtypes[i] if len(proargtypes) > i else '', + proargnames[i] if len(proargnames) > i else '', + proargdefaultvals[i] if len(proargdefaultvals) > i else '' + ) + for i in range(len(proargtypes))]} + + # Prepare string formatted Argument to be displayed in the Properties + # panel. + + proargs = [self._map_arguments_list( + proargmodes_fltrd[i] if len(proargmodes_fltrd) > i else '', + proargtypes[i] if len(proargtypes) > i else '', + proargnames[i] if len(proargnames) > i else '', + proargdefaultvals[i] if len(proargdefaultvals) > i else '' + ) + for i in range(len(proargtypes))] + + proargs = {"proargs": ", ".join(proargs)} + + return params, proargs + + def _map_arguments_dict(self, argid, argmode, argtype, argname, argdefval): + """ + Returns Dict of formatted Arguments. + Args: + argid: Argument Sequence Number + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + return {"argid": argid, + "argtype": argtype.strip() if argtype is not None else '', + "argmode": argmode, + "argname": argname, + "argdefval": argdefval} + + def _map_arguments_list(self, argmode, argtype, argname, argdef): + """ + Returns List of formatted Arguments. + Args: + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + arg = '' + + if argmode: + arg += argmode + " " + if argname: + arg += argname + " " + if argtype: + arg += argtype + " " + if argdef: + arg += " DEFAULT " + argdef + + return arg + + def _format_proacl_from_db(self, proacl): + """ + Returns privileges. + Args: + proacl: Privileges Dict + """ + privileges = [] + for row in proacl: + priv = parse_priv_from_db(row) + privileges.append(priv) + + return {"acl": privileges} + + @check_precondition + def types(self, gid, sid, did, scid, fnid=None): + """ + Returns the Data Types. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + condition = "(typtype IN ('b', 'c', 'd', 'e', 'p', 'r') AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger'))" + if self.blueprint.show_system_objects: + condition += " AND nspname NOT LIKE E'pg\\\\_toast%' AND nspname NOT LIKE E'pg\\\\_temp%'" + + # Get Types + status, types = self.get_types(self.conn, condition) + + if not status: + return internal_server_error(errormsg=types) + + return make_json_response( + data=types, + status=200 + ) + + @check_precondition + def get_languages(self, gid, sid, did, scid, fnid=None): + """ + Returns the Languages list. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_languages.sql']) + ) + status, rows = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res + rows['rows'] + + return make_json_response( + data=res, + status=200 + ) + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + current_app.logger.error(traceback.print_exception( + exc_type, + exc_value, + exc_traceback, + limit=2 + ) + ) + + return internal_server_error(errormsg=str(exc_value)) + + @check_precondition + def variable_options(self, gid, sid, did, scid, fnid=None): + """ + Returns the variables. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + This function will return list of variables available for + table spaces. + """ + SQL = render_template( + "/".join([self.sql_template_path, 'variables.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=rset) + + return make_json_response( + data=rset['rows'], + status=200 + ) + + @check_precondition + @validate_request + def create(self, gid, sid, did, scid): + """ + Create a new Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + Function object in json format. + """ + + try: + # Get SQL to create Function + status, SQL = self._get_sql(gid, sid, did, scid, self.request) + if not status: + return internal_server_error(errormsg=SQL) + + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join([self.sql_template_path, + 'get_oid.sql']), + nspname=self.request['pronamespace'], + name=self.request['name']) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res['rows'][0] + + return jsonify( + node=self.blueprint.generate_browser_node( + res['oid'], + self.request['pronamespace'], + res['name'], + icon="icon-" + self.node_type, + language=res['lanname'], + funcowner=res['funcowner'] + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, fnid): + """ + Drop the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Fetch Name and Schema Name to delete the Function. + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), scid=scid, fnid=fnid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + name, func_args, nspname = res['rows'][0] + + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), + name=name, + func_args=func_args, + nspname=nspname, + 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("Function Dropped."), + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + @validate_request + def update(self, gid, sid, did, scid, fnid): + """ + Update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + + if not status: + return internal_server_error(errormsg=SQL) + + 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) + + return make_json_response( + success=1, + info="Function Updated.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, fnid=None): + """ + Returns the SQL for the Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.node_type == 'procedure': + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get SQL to create Function + status, func_def = self._get_sql(gid, sid, did, scid, resp_data, + None, True) + if not status: + return internal_server_error(errormsg=func_def) + + name = resp_data['name'] + else: + # Fetch the function definition. + SQL = render_template("/".join([self.sql_template_path, + 'get_definition.sql']), fnid=fnid, scid=scid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + func_def, name = res['rows'][0] + + sql_header = """-- {0}: {1} + +-- DROP {0} {1}; + +""".format(self.node_type.upper(), name) + + SQL = sql_header + func_def + + return ajax_response(response=SQL) + + @check_precondition + @validate_request + def msql(self, gid, sid, did, scid, fnid=None): + """ + Returns the modified SQL. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + Returns: + SQL statements to create/update the Domain. + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + if status: + return make_json_response( + data=SQL, + status=200 + ) + else: + return SQL + + def _get_sql(self, gid, sid, did, scid, data, fnid=None, is_sql=False): + """ + Generates the SQL statements to create/update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + data: Function data + fnid: Function Id + """ + + try: + vol_dict = {'v': 'VOLATILE', 's': 'STABLE', 'i': 'IMMUTABLE'} + + # Get Schema Name from its OID. + if 'pronamespace' in data: + data['pronamespace'] = self._get_schema(data[ + 'pronamespace']) + if 'provolatile' in data: + data['provolatile'] = vol_dict[data['provolatile']] + + if fnid is not None: + # Edit Mode + + # Fetch Old Data from database. + old_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get Schema Name + old_data['pronamespace'] = self._get_schema(old_data[ + 'pronamespace']) + + if 'provolatile' in old_data: + old_data['provolatile'] = vol_dict[old_data['provolatile']] + + # If any of the below argument is changed, + # then CREATE OR REPLACE SQL statement should be called + fun_change_args = ['lanname', 'prosrc', 'probin', 'prosrc_c', + 'provolatile', 'proisstrict', 'prosecdef', + 'procost', 'proleakproof', 'arguments'] + + data['change_func'] = False + for arg in fun_change_args: + if arg == 'arguments' and arg in data and len(data[arg]) \ + > 0: + data['change_func'] = True + elif arg in data: + data['change_func'] = True + + # If Function Definition/Arguments are changed then merge old + # Arguments with changed ones for Create/Replace Function + # SQL statement + if 'arguments' in data and len(data['arguments']) > 0: + for arg in data['arguments']['changed']: + for old_arg in old_data['arguments']: + if arg['argid'] == old_arg['argid']: + old_arg.update(arg) + break + data['arguments'] = old_data['arguments'] + elif data['change_func']: + data['arguments'] = old_data['arguments'] + + # Parse Privileges + if 'acl' in data: + for key in ['added', 'deleted', 'changed']: + if key in data['acl']: + data['acl'][key] = parse_priv_to_db( + data['acl'][key], ["X"]) + + # Parse Variables + chngd_variables = {} + data['merged_variables'] = [] + old_data['chngd_variables'] = {} + del_variables = {} + + # If Function Definition/Arguments are changed then, + # Merge old, new (added, changed, deleted) variables, + # which will be used in the CREATE or REPLACE Function sql + # statement + + if data['change_func']: + # To compare old and new variables, preparing name : + # value dict + + # Deleted Variables + if 'variables' in data and 'deleted' in data['variables']: + for v in data['variables']['deleted']: + del_variables[v['name']] = v['value'] + + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + chngd_variables[v['name']] = v['value'] + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + chngd_variables[v['name']] = v['value'] + + for v in old_data['variables']: + old_data['chngd_variables'][v['name']] = v['value'] + + # Prepare final dict of new and old variables + for name, val in old_data['chngd_variables'].items(): + if name not in chngd_variables and name not in \ + del_variables: + chngd_variables[name] = val + + # Prepare dict in [{'name': var_name, 'value': var_val},..] + # format + for name, val in chngd_variables.items(): + data['merged_variables'].append({'name': name, + 'value': val}) + else: + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + data['merged_variables'].append(v) + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + data['merged_variables'].append(v) + + SQL = render_template( + "/".join([self.sql_template_path, 'update.sql']), + data=data, o_data=old_data + ) + else: + # Parse Privileges + if 'acl' in data: + data['acl'] = parse_priv_to_db(data['acl'], ["X"]) + + args = '' + cnt = 1 + if 'arguments' in data: + for a in data['arguments']: + if (('argmode' in a and a['argmode'] != 'OUT' and + a['argmode'] is not None + ) or 'argnode' not in a): + if 'argmode' in a: + args += a['argmode'] + " " + if 'argname' in a and a['argname'] != ''\ + and a['argname'] is not None: + args += self.qtIdent( + self.conn, a['argname']) + " " + if 'argtype' in a: + args += a['argtype'] + if cnt < len(data['arguments']): + args += ', ' + cnt += 1 + + data['func_args'] = args.strip(' ') + # Create mode + SQL = render_template("/".join([self.sql_template_path, + 'create.sql']), + data=data, is_sql=is_sql) + return True, SQL.strip('\n') + + except Exception as e: + return False, e + + def _fetch_properties(self, gid, sid, did, scid, fnid=None): + """ + Return Function Properties which will be used in properties, + msql function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = {} + + SQL = render_template("/".join([self.sql_template_path, + 'properties.sql']), + scid=scid, fnid=fnid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + resp_data = res['rows'][0] + + # Get formatted Arguments + frmtd_params, frmtd_proargs = self._format_arguments_from_db(resp_data) + resp_data.update(frmtd_params) + resp_data.update(frmtd_proargs) + + # Fetch privileges + SQL = render_template("/".join([self.sql_template_path, 'acl.sql']), + fnid=fnid) + status, proaclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Get Formatted Privileges + resp_data.update(self._format_proacl_from_db(proaclres['rows'])) + + # Set System Functions Status + resp_data['sysfunc'] = False + if fnid <= self.manager.db_info[did]['datlastsysoid']: + resp_data['sysfunc'] = True + + # Get formatted Security Labels + if 'seclabels' in resp_data: + resp_data.update(parse_sec_labels_from_db(resp_data['seclabels'])) + + # Get formatted Variable + resp_data.update(parse_variables_from_db([ + {"setconfig": resp_data['proconfig']}])) + + return resp_data + + def _get_schema(self, scid): + """ + Returns Schema Name from its OID. + + Args: + scid: Schema Id + """ + SQL = render_template("/".join([self.sql_template_path, + '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 dependents(self, gid, sid, did, scid, fnid): + """ + This function get the dependents and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependents_result = self.get_dependents(self.conn, fnid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, fnid): + """ + This function get the dependencies and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependencies_result = self.get_dependencies(self.conn, fnid) + return ajax_response( + response=dependencies_result, + status=200 + ) + +FunctionView.register_node_view(blueprint) + + +class ProcedureModule(SchemaChildModule): + """ + class ProcedureModule(SchemaChildModule): + + This class represents The Procedures Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Procedures Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Procedures collection node. + + * node_inode(): + - Returns Procedures node as leaf node. + + * script_load() + - Load the module script for Procedures, when schema node is + initialized. + + """ + + NODE_TYPE = 'procedure' + COLLECTION_LABEL = gettext("Procedures") + + def __init__(self, *args, **kwargs): + """ + Initialize the Procedure Module. + Args: + *args: + **kwargs: + """ + super(ProcedureModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = ['ppas'] + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Procedures collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Procedures, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + +procedure_blueprint = ProcedureModule(__name__) + + +class ProcedureView(FunctionView): + + node_type = procedure_blueprint.node_type + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(ProcedureView, self).__init__(*args, **kwargs) + + @property + def required_args(self): + """ + Returns Required arguments for procedures node. + Where + Required Args: + name: Name of the Function + pronamespace: Function Namespace + lanname: Function Language Name + prosrc: Function Code + """ + return ['name', + 'pronamespace', + 'lanname', + 'prosrc'] + + def module_js(self): + """ + Load JS file (procedures.js) for this module. + """ + + return make_response( + render_template( + "procedure/js/procedures.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + +ProcedureView.register_node_view(procedure_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png new file mode 100644 index 0000000000000000000000000000000000000000..c44874e5574e624c2687689ac75f3ba4ed69e811 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE0CVL=8;#?*`-(h^sRi9 z*>&~c)34PF?}pc0oO}FT&eYpg3!lCJ{{QpuKPl}Gawb0N+VtXry&)e^8)He3UoeBi zvm0qZ4rhT!WHFHT0Ash4*>*riqNj^vh{WaCes{hD1{^FOt?qvPzrI(~vFzEgEEaCT zKn8&fCc|T@oHyDw|30!InX~Vp=DDQ@|E}SiWNDf1d5o{vOS9^<jH6JQ%!{XA68~=T zUVHU-(WR)_zZZZ1_xt(xjh~rXW-{}Bc$;4hv`n?cHKHUXu_V<hxhNG#F&G&b8tNJt z>Kd7b7@Arcm|Gc`Y8#kY85l5Do_~m<AvZrIGp!P&!9dr*5~wG{$k@un#LB=-+W@H3 U;MDZcH9!pvp00i_>zopr06KSqcmMzZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..7c13a9bc73a782b5139095af596e15d7b68dd20c GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9EC%sCbm^nUN&dsC)d z%g%m(?%cJOmUB^2&)2TKR$To5`}b?r)x6ex&wxr9OM?7@862M7NCR>>3p^r=fwTu0 zyPeFo12PglT^vI=t|uoXgaoB9FsmgiGa57px_XMbaBFHxO0zOZW@WzA@{)3Bd#1Ev zf>nS=wRyl)0gsIDYK$8M1T>mj(wGjaEU<j_)L{XKVdhn(2@iX`tkM;(8Sb=j%x%8O z&&KdzmZ)RwGzMRwWvV5v5hW>!C8<`)MX5lF!N|bSP}jgv*T^))(A3Jn+{)NY+rZ4q zz+j);rTHita`RI%(<(t440H`FfqFuWjIB&etPFq}fI1CMO%GiI)WG2B>gTe~DWM4f DC&Fq! literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png new file mode 100644 index 0000000000000000000000000000000000000000..656854a0191b5dd5d465f90cfbceebdc3913f1a2 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF3h)VW1=3U3Jn||!yY$MRhadm{ z{r~UY=bu~de4cgqZS9ih={*lqIv$kGe$v0=Wy+ox+kmPWOM?7@862M7NCR>>3p^r= zfwTu0yPeFo12Td<T^vI=t|uorFgbMz%nH2e!Eh#_sIZa4a8(-{W2?l}DN`<8YH;#- zst}-Z;J_6|HZC3?W5<L^3=wBng(l?o+}ds4$eUzU%$C*nPL(la_XP%qilxGbk7sB! z0Zmseag8WRNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KrrHLkRt5(1-s!DE(U6;; ll9^Ts(O_T+)&Nv(Vr5_k(Qs;d=o+8~22WQ%mvv4FO#sGkaAg1h literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..8b65dff9eb2c373df031669adba7a82c0ae2aaa6 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9Cs%{mqo^m6CUA1_|~ z|NHmbqerjy?R&Ir+0E|mOJ!vji;J%}H<uLMy$n>!SQ6wH%;50sMjDXAS>O>_45U54 z*zIJt9gq>^>Eal|aXmS~fyt>$U{>Hw4~8=dMTLzVhO64x7+WQ#PMLD)QiGGvQ-uJP z0|%}!vT^bF7&|6RVu(1qDl{Rt=hklXM&2Z=Vz#WlMH3iS#bz)t#6K1K?su<o8qjpr z64!{5l*E!$tK_0oAjM#0U}&goV5n<k8e(W_WngY)Y^H5sW@TWoPwvuu6b-rgDVb@N pAPok(29`iQAx6elCMH$}Kn*~h2B)Tnt^sOb@O1TaS?83{1OQh#ZFT?v literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css new file mode 100644 index 0000000..16b2e71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css @@ -0,0 +1,3 @@ +.functions_code { + height: 130px !important; +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js new file mode 100644 index 0000000..b0a5d1c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js @@ -0,0 +1,438 @@ +/* Create and Register Function Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.browser.collection', 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-function']) { + var functions = pgAdmin.Browser.Nodes['coll-function'] = + pgAdmin.Browser.Collection.extend({ + node: 'function', + label: '{{ _('Functions') }}', + type: 'coll-function', + columns: ['name', 'funcowner', 'description'] + }); + }; + + // Security Model + var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({ + defaults: { + provider: null, + label: null + }, + schema: [{ + id: 'provider', label: '{{ _('Provider') }}', + type: 'text', editable: true, cellHeaderClasses:'width_percent_50' + },{ + id: 'security_label', label: '{{ _('Security Label') }}', + type: 'text', editable: true, cellHeaderClasses:'width_percent_50' + }], + validate: function() { + var err = {}, + errmsg = null, + data = this.toJSON(); + + if (_.isUndefined(data.label) || + _.isNull(data.label) || + String(data.label).replace(/^\s+|\s+$/g, '') == '') { + return _("Please specify the value for all the security providers."); + } + return null; + } + }); + + // Argument Model + var ArgumentModel = pgAdmin.Browser.Node.Model.extend({ + idAttribute: 'argid', + defaults: { + argid: undefined, + argtype: undefined, + argmode: undefined, + argname: undefined, + argdefval: undefined + }, + schema: [{ + id: 'argid', visible: false, type: 'text', + mode: ['properties', 'edit','create'] + },{ + id: 'argtype', label:'{{ _('Data Type') }}', cell: + 'node-ajax-options', cellHeaderClasses: 'width_percent_30', + control: 'node-ajax-options', type: 'text', url: 'get_types', + editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + }, first_empty: true + },{ + id: 'argmode', label:'{{ _('Mode') }}', type: 'options', + control: 'node-ajax-options', cellHeaderClasses:'width_percent_20', + options:[ + {'label': 'IN', 'value': 'IN'}, + {'label': 'OUT', 'value': 'OUT'}, + {'label': 'INOUT', 'value': 'INOUT'}, + {'label': 'VARIADIC', 'value': 'VARIADIC'} + ], editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argname', label:'{{ _('Argument Name') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_30', + },{ + id: 'argdefval', label:'{{ _('Default Value') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_20' + } + ], + toJSON: Backbone.Model.prototype.toJSON + }); + + if (!pgBrowser.Nodes['function']) { + pgAdmin.Browser.Nodes['function'] = pgBrowser.Node.extend({ + type: 'function', + label: '{{ _('Function') }}', + collection_type: 'coll-function', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function(args) { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + pgBrowser.add_menus([{ + name: 'create_function_on_coll', node: 'coll-function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: false}, + enable: 'canCreate' + } + ]); + + }, + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + schema_id = args.node_info.schema._id + this.set({'pronamespace': schema_id}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'funcowner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + defaults: { + name: undefined, + oid: undefined, + xmin: undefined, + funcowner: undefined, + pronamespace: undefined, + description: undefined, + pronargs: undefined, /* Argument Count */ + proargs: undefined, /* Arguments */ + proargtypenames: undefined, /* Argument Signature */ + prorettypename: undefined, /* Return Type */ + lanname: 'sql', /* Language Name in which function is being written */ + provolatile: undefined, /* Volatility */ + proretset: undefined, /* Return Set */ + proisstrict: undefined, + prosecdef: undefined, /* Security of definer */ + proiswindow: undefined, /* Window Function ? */ + procost: undefined, /* Estimated execution Cost */ + prorows: undefined, /* Estimated number of rows */ + proleakproof: undefined, + arguments: [], + prosrc: undefined, + prosrc_c: undefined, + probin: '$libdir/', + options: [], + variables: [], + proacl: undefined, + seclabels: [], + acl: [], + sysfunc: undefined + }, + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'] + },{ + id: 'oid', label: '{{ _('OID') }}', cell: 'string', + type: 'text' , mode: ['properties'] + },{ + id: 'funcowner', label: '{{ _('Owner') }}', cell: 'string', + control: Backform.NodeListByNameControl, node: 'role', type: + 'text', disabled: 'isDisabled' + },{ + id: 'pronamespace', label: '{{ _('Schema') }}', cell: 'string', + control: 'node-list-by-id', type: 'text', cache_level: 'database', + node: 'schema' + },{ + id: 'sysfunc', label: '{{ _('System Function?') }}', + cell:'boolean', type: 'switch', + mode: ['properties'] + },{ + id: 'description', label: '{{ _('Comment') }}', cell: 'string', + type: 'multiline' + },{ + id: 'pronargs', label: '{{ _('Argument Count') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties'] + },{ + id: 'proargs', label: '{{ _('Arguments') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties', 'edit'], + disabled: 'isDisabled' + },{ + id: 'proargtypenames', label: '{{ _('Signature Arguments') }}', cell: + 'string', type: 'text', group: '{{ _('Definition') }}', mode: ['properties'], + disabled: 'isDisabled' + },{ + id: 'prorettypename', label: '{{ _('Return Type') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_types', disabled: 'isDisabled', first_empty: true, + mode: ['create'] + },{ + id: 'prorettypename', label: '{{ _('Return Type') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: true, + mode: ['properties', 'edit'] + }, { + id: 'lanname', label: '{{ _('Language') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_languages', disabled: 'isDisabled' + },{ + id: 'prosrc', label: '{{ _('Code') }}', cell: 'string', + type: 'multiline', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { + return false; + } + return true; + }, maxlength: '', extraClasses: ['functions_code'] + },{ + id: 'probin', label: '{{ _('Object File') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'prosrc_c', label: '{{ _('Link Symbol') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'provolatile', label: '{{ _('Volatility') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Options') }}', + options:[ + {'label': 'VOLATILE', 'value': 'v'}, + {'label': 'STABLE', 'value': 's'}, + {'label': 'IMMUTABLE', 'value': 'i'}, + ], disabled: 'isDisabled' + },{ + id: 'proretset', label: '{{ _('Returns a Set?') }}', group: '{{ _('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'proisstrict', label: '{{ _('Strict?') }}', group: '{{ _ + ('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'prosecdef', label: '{{ _('Security of definer?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'proiswindow', label: '{{ _('Window?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'procost', label: '{{ _('Estimated Cost') }}', group: '{{ _('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled' + },{ + id: 'prorows', label: '{{ _('Estimated Rows') }}', group: '{{ _ + ('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled', + deps: ['proretset'] + },{ + id: 'proleakproof', label: '{{ _('Leak proof?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', min_version: 90200, + disabled: 'isDisabled' + },{ + id: 'proacl', label: '{{ _('Privileges') }}', + group: '{{ _('Security') }}', cell:'boolean', type: 'text', cell: 'string', + mode: ['properties'] + },{ + id: 'arguments', label: '{{ _('Parameters') }}', cell: 'string', + group: '{{ _('Parameters') }}', type: 'collection', canAdd: function(m){ + return m.isNew(); + }, + canDelete: true, model: ArgumentModel, mode: + ['create', 'edit'], editable: false, + columns: ['argtype', 'argmode', 'argname', 'argdefval'] + },{ + id: 'variables', label: '{{ _('Variables') }}', type: 'collection', + group: '{{ _('Variables') }}', control: 'variable-collection', + model: pgAdmin.Browser.Node.VariableModel, + mode: ['edit', 'create'], canAdd: 'canVarAdd', canEdit: false, + canDelete: true, disabled: 'isDisabled' + },{ + id: 'acl', label: '{{ _('Privileges') }}', model: pgAdmin + .Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['X']}), uniqueCol : ['grantee', 'grantor'], + editable: false, type: 'collection', group: '{{ _('Security') }}', + mode: ['edit', 'create'], + canAdd: true, canDelete: true, control: 'unique-col-collection', + }, + { + id: 'seclabels', label: '{{ _('Security Labels') }}', + model: SecurityModel, type: 'collection', + group: '{{ _('Security') }}', mode: ['edit', 'create'], + min_version: 90100, canAdd: true, + canEdit: true, canDelete: true, + control: 'unique-col-collection', uniqueCol : ['provider'] + } + ], + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('funcowner')) || String(this.get('funcowner')).replace(/^\s+|\s+$/g, '') == '') { + err['funcowner'] = '{{ _('Owner can not be empty!') }}'; + errmsg = errmsg || err['funcowner']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('prorettypename')) || String(this.get('prorettypename')).replace(/^\s+|\s+$/g, '') == '') { + err['prorettypename'] = '{{ _('Return Type can not be empty!') }}'; + errmsg = errmsg || err['prorettypename']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (String(this.get('lanname')) == 'c') { + if (_.isUndefined(this.get('probin')) || String(this.get('probin')) + .replace(/^\s+|\s+$/g, '') == '') { + err['probin'] = '{{ _('Object File can not be empty!') }}'; + errmsg = errmsg || err['probin']; + } + + if (_.isUndefined(this.get('prosrc_c')) || String(this.get('prosrc_c')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc_c'] = '{{ _('Link Symbol can not be empty!') }}'; + errmsg = errmsg || err['prosrc_c']; + } + } + else { + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + } + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + return null; + }, + isDisabled: function(m){ + name = this.name; + switch(name){ + case 'proargs': + case 'proargtypenames': + case 'proretset': + case 'proiswindow': + return !m.isNew(); + break; + case 'prorows': + if(m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return false; + break; + } + }, + canVarAdd: function(m) { + return true; + } + }), + 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 Function + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-function' == d._type) { + //Check if we are not child of catalog + 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['function']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql new file mode 100644 index 0000000..1c88f47 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql @@ -0,0 +1,53 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proisstrict %}STRICT {% endif %}{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.proiswindow %}WINDOW{% endif -%}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif %}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif %} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql new file mode 100644 index 0000000..0072198 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql @@ -0,0 +1,105 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif %}{% endif %} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif %} +{% endif %}{% endif %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql new file mode 100644 index 0000000..50de6dc --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor -%} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif -%} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql new file mode 100644 index 0000000..0126c8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql new file mode 100644 index 0000000..ec9f23f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql new file mode 100644 index 0000000..1a0c3eb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..1c88f47 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,53 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proisstrict %}STRICT {% endif %}{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.proiswindow %}WINDOW{% endif -%}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif %}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif %} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..0072198 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,105 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif %}{% endif %} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif %} +{% endif %}{% endif %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..50de6dc --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor -%} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif -%} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..c24970c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,22 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade%} CASCADE{% +endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..0126c8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..ec9f23f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..1a0c3eb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js new file mode 100644 index 0000000..f50ffe9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js @@ -0,0 +1,171 @@ +/* Create and Register Procedure Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.node.function', 'pgadmin.browser.collection', + 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify, Function) { + + if (!pgBrowser.Nodes['coll-procedure']) { + var procedures = pgAdmin.Browser.Nodes['coll-procedure'] = + pgAdmin.Browser.Collection.extend({ + node: 'procedure', + label: '{{ _('Procedures') }}', + type: 'coll-procedure', + columns: ['name', 'funcowner', 'description'] + }); + }; + + pgSchemaNode = pgBrowser.Nodes['schema']; + + // Inherit Functions Node + if (!pgBrowser.Nodes['procedure']) { + pgAdmin.Browser.Nodes['procedure'] = Function.extend({ + type: 'procedure', + label: '{{ _('Procedure') }}', + collection_type: 'coll-procedure', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.proc_initialized) + return; + + this.proc_initialized = true; + + pgBrowser.add_menus([{ + name: 'create_procedure_on_coll', node: 'coll-procedure', module: + this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + false} + },{ + name: 'create_procedure', node: 'procedure', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, + },{ + name: 'create_procedure', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, enable: 'canCreateProc' + } + ]); + }, + canDrop: pgSchemaNode.canChildDrop, + canDropCascade: pgSchemaNode.canChildDrop, + model: Function.model.extend({ + defaults: _.extend({}, + Function.model.prototype.defaults, + { + lanname: 'edbspl' + } + ), + canVarAdd: function(m){ + var server = this.node_info.server; + if (server.version < 90500) { + return false; + } + else { + return true; + } + }, + isDisabled: function(m) { + name = this.name; + switch(name){ + case 'provolatility': + case 'proisstrict': + case 'prosecdef': + case 'procost': + case 'proleakproof': + case 'variables': + var server = this.node_info.server; + if (server.version < 90500) { + return true; + } + else { + return false; + } + break; + case 'prorows': + var server = this.node_info.server; + if(server.version >= 90500 && m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return true; + break; + } + }, + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + return null; + }, + } + ), + canCreateProc: function(itemData, item, data) { + var node_hierarchy = this.getTreeNodeHierarchy.apply(this, [item]); + + // Do not provide Create option in catalog + if ('catalog' in node_hierarchy) + return false; + + // Procedures supported only in PPAS + if ('server' in node_hierarchy && node_hierarchy['server'].type == "ppas") + return true; + + return false; + + } + }); + + } + + return pgBrowser.Nodes['procedure']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..8630912 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,33 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..e60e602 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,82 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..1f7690d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,33 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor -%}){% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..42030b3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,78 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} +AS {% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..12f5ad2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,43 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor -%}){% endif %} + + {{ data.provolatile }}{% if data.proleakproof %}LEAKPROOF {% elif not data.proleakproof %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..54c1d84 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,102 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + {% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% else %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'PROCEDURE', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'PROCEDURE', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABLE.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABLE.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros index 08d1198..1ac4cea 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros @@ -1,13 +1,9 @@ {##############################################} {# Macros for Privileges (functions module) #} {##############################################} -{% macro SET(conn, type, role, param, privs, with_grant_privs, schema, func_args) -%} -{% if privs %} -GRANT {{ privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{conn|qtIdent(role) }}; -{% endif %} -{% if with_grant_privs %} -GRANT {{ with_grant_privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{ conn|qtIdent(role) }} WITH GRANT OPTION; -{% endif %} +{% macro SET(conn, type, role, param, privs, with_grant_privs, schema, func_args) -%}{% if privs %} +GRANT {{ privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{conn|qtIdent(role) }};{% endif %}{% if with_grant_privs %} +GRANT {{ with_grant_privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{ conn|qtIdent(role) }} WITH GRANT OPTION;{% endif %} {%- endmacro %} {% macro UNSETALL(conn, type, role, param, schema, func_args) -%} REVOKE ALL ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) FROM {{conn|qtIdent(role) }}; ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-23 12:03 Dave Page <[email protected]> parent: Khushboo Vashi <[email protected]> 0 siblings, 2 replies; 11+ messages in thread From: Dave Page @ 2016-03-23 12:03 UTC (permalink / raw) To: Khushboo Vashi <[email protected]>; +Cc: pgadmin-hackers On Tue, Mar 22, 2016 at 10:51 AM, Khushboo Vashi <[email protected]> wrote: > Hi, > > Please find updated Patch for the Functions/Procedures Module. Hi Unfortunately I found more issues as I tested in-depth. I've attached an updated patch in which I've done some cleanup - additional comments below: - Some argument lists are shown with an extra space, e.g. character varying , integer (pem.create_agent(character varying , integer)) - A 404 error is seen when functions are selected under a Catalog node. - Procedures have a property of "System function?" - should be "System procedure?" - The Return Type, Returns a Set and Window fields should be hidden for Procedures. - When creating a procedure (below), I get the following error: ----- -- PROCEDURE: foo -- DROP PROCEDURE foo; CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT b integer DEFAULT -) VOLATILE NOT LEAKPROOF SECURITY DEFINER COST 100.0 AS BEGIN b:=a+b+1; END; COMMENT ON PROCEDURE public.foo IS 'Foo procedure'; ----- ----- 2016-03-23 11:22:02,186: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 11:22:02] "GET /browser/procedure/obj/1/2/14844/13627/16387 HTTP/1.1" 500 - Traceback (most recent call last): File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__ return self.wsgi_app(environ, start_response) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app response = self.make_response(self.handle_exception(e)) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception reraise(exc_type, exc_value, tb) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app response = self.full_dispatch_request() File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request rv = self.handle_user_exception(e) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception reraise(exc_type, exc_value, tb) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request rv = self.dispatch_request() File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", line 84, in view return self.dispatch_request(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line 233, in dispatch_request return method(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", line 349, in wrap return f(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", line 425, in properties resp_data = self._fetch_properties(gid, sid, did, scid, fnid) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", line 1097, in _fetch_properties resp_data = res['rows'][0] IndexError: list index out of range ----- - After a Python server reset, I get the following error when trying to view SQL of a Procedure (seems like it thinks it's connected to PG?): TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql 2016-03-23 11:28:52,852: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 11:28:52] "GET /browser/procedure/nodes/1/2/14844/2200/ HTTP/1.1" 500 - Traceback (most recent call last): File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__ return self.wsgi_app(environ, start_response) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app response = self.make_response(self.handle_exception(e)) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception reraise(exc_type, exc_value, tb) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app response = self.full_dispatch_request() File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request rv = self.handle_user_exception(e) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception reraise(exc_type, exc_value, tb) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request rv = self.dispatch_request() File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", line 84, in view return self.dispatch_request(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line 233, in dispatch_request return method(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", line 349, in wrap return f(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", line 390, in nodes 'node.sql']), scid=scid) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", line 127, in render_template return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", line 830, in get_or_select_template return self.get_template(template_name_or_list, parent, globals) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", line 791, in get_template return self._load_template(name, self.make_globals(globals)) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", line 765, in _load_template template = self.loader.load(self, name, globals) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/loaders.py", line 113, in load source, filename, uptodate = self.get_source(environment, name) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", line 64, in get_source raise TemplateNotFound(template) TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql 2016-03-23 11:28:57,953: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 11:28:57] "POST /ping HTTP/1.1" 200 - - Procedures do not include the schema name in the headers of reverse engineered SQL, e.g. - What's the trailing - in the parameter list in this reverse engineered SQL? -- PROCEDURE: foo -- DROP PROCEDURE foo; CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT b integer DEFAULT -) VOLATILE NOT LEAKPROOF SECURITY DEFINER COST 100.0 AS BEGIN b:=a+b+1; END; COMMENT ON PROCEDURE public.foo IS 'Foo procedure'; Thanks! -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-23 13:44 Khushboo Vashi <[email protected]> parent: Dave Page <[email protected]> 1 sibling, 1 reply; 11+ messages in thread From: Khushboo Vashi @ 2016-03-23 13:44 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi Dave, I think you forgot to attach the updated patch. Thanks, Khushboo On Wed, Mar 23, 2016 at 5:33 PM, Dave Page <[email protected]> wrote: > On Tue, Mar 22, 2016 at 10:51 AM, Khushboo Vashi > <[email protected]> wrote: > > Hi, > > > > Please find updated Patch for the Functions/Procedures Module. > > Hi > > Unfortunately I found more issues as I tested in-depth. I've attached > an updated patch in which I've done some cleanup - additional comments > below: > > - Some argument lists are shown with an extra space, e.g. > > character varying , integer > > (pem.create_agent(character varying , integer)) > > - A 404 error is seen when functions are selected under a Catalog node. > > - Procedures have a property of "System function?" - should be "System > procedure?" > > - The Return Type, Returns a Set and Window fields should be hidden > for Procedures. > > - When creating a procedure (below), I get the following error: > > ----- > -- PROCEDURE: foo > > -- DROP PROCEDURE foo; > > CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT > b integer DEFAULT -) > VOLATILE NOT LEAKPROOF SECURITY DEFINER > COST 100.0 > AS > > BEGIN > b:=a+b+1; > END; > > COMMENT ON PROCEDURE public.foo > IS 'Foo procedure'; > ----- > > ----- > 2016-03-23 11:22:02,186: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 > 11:22:02] "GET /browser/procedure/obj/1/2/14844/13627/16387 HTTP/1.1" > 500 - > Traceback (most recent call last): > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1836, in __call__ > return self.wsgi_app(environ, start_response) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1820, in wsgi_app > response = self.make_response(self.handle_exception(e)) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1403, in handle_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1817, in wsgi_app > response = self.full_dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1477, in full_dispatch_request > rv = self.handle_user_exception(e) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1381, in handle_user_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1475, in full_dispatch_request > rv = self.dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1461, in dispatch_request > return self.view_functions[rule.endpoint](**req.view_args) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", > line 84, in view > return self.dispatch_request(*args, **kwargs) > File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line > 233, in dispatch_request > return method(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 349, in wrap > return f(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 425, in properties > resp_data = self._fetch_properties(gid, sid, did, scid, fnid) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 1097, in _fetch_properties > resp_data = res['rows'][0] > IndexError: list index out of range > ----- > > - After a Python server reset, I get the following error when trying > to view SQL of a Procedure (seems like it thinks it's connected to > PG?): > > TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql > 2016-03-23 11:28:52,852: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 > 11:28:52] "GET /browser/procedure/nodes/1/2/14844/2200/ HTTP/1.1" 500 > - > Traceback (most recent call last): > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1836, in __call__ > return self.wsgi_app(environ, start_response) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1820, in wsgi_app > response = self.make_response(self.handle_exception(e)) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1403, in handle_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1817, in wsgi_app > response = self.full_dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1477, in full_dispatch_request > rv = self.handle_user_exception(e) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1381, in handle_user_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1475, in full_dispatch_request > rv = self.dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1461, in dispatch_request > return self.view_functions[rule.endpoint](**req.view_args) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", > line 84, in view > return self.dispatch_request(*args, **kwargs) > File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line > 233, in dispatch_request > return method(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 349, in wrap > return f(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 390, in nodes > 'node.sql']), scid=scid) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", > line 127, in render_template > return > _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", > line 830, in get_or_select_template > return self.get_template(template_name_or_list, parent, globals) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", > line 791, in get_template > return self._load_template(name, self.make_globals(globals)) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", > line 765, in _load_template > template = self.loader.load(self, name, globals) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/loaders.py", > line 113, in load > source, filename, uptodate = self.get_source(environment, name) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", > line 64, in get_source > raise TemplateNotFound(template) > TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql > 2016-03-23 11:28:57,953: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 > 11:28:57] "POST /ping HTTP/1.1" 200 - > > - Procedures do not include the schema name in the headers of reverse > engineered SQL, e.g. > > - What's the trailing - in the parameter list in this reverse engineered > SQL? > > -- PROCEDURE: foo > > -- DROP PROCEDURE foo; > > CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT > b integer DEFAULT -) > VOLATILE NOT LEAKPROOF SECURITY DEFINER > COST 100.0 > AS > > BEGIN > b:=a+b+1; > END; > > COMMENT ON PROCEDURE public.foo > IS 'Foo procedure'; > > Thanks! > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-23 14:01 Dave Page <[email protected]> parent: Khushboo Vashi <[email protected]> 0 siblings, 0 replies; 11+ messages in thread From: Dave Page @ 2016-03-23 14:01 UTC (permalink / raw) To: Khushboo Vashi <[email protected]>; +Cc: pgadmin-hackers Ooops :-) On Wed, Mar 23, 2016 at 1:44 PM, Khushboo Vashi <[email protected]> wrote: > Hi Dave, > > I think you forgot to attach the updated patch. > > Thanks, > Khushboo > > On Wed, Mar 23, 2016 at 5:33 PM, Dave Page <[email protected]> wrote: >> >> On Tue, Mar 22, 2016 at 10:51 AM, Khushboo Vashi >> <[email protected]> wrote: >> > Hi, >> > >> > Please find updated Patch for the Functions/Procedures Module. >> >> Hi >> >> Unfortunately I found more issues as I tested in-depth. I've attached >> an updated patch in which I've done some cleanup - additional comments >> below: >> >> - Some argument lists are shown with an extra space, e.g. >> >> character varying , integer >> >> (pem.create_agent(character varying , integer)) >> >> - A 404 error is seen when functions are selected under a Catalog node. >> >> - Procedures have a property of "System function?" - should be "System >> procedure?" >> >> - The Return Type, Returns a Set and Window fields should be hidden >> for Procedures. >> >> - When creating a procedure (below), I get the following error: >> >> ----- >> -- PROCEDURE: foo >> >> -- DROP PROCEDURE foo; >> >> CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT >> b integer DEFAULT -) >> VOLATILE NOT LEAKPROOF SECURITY DEFINER >> COST 100.0 >> AS >> >> BEGIN >> b:=a+b+1; >> END; >> >> COMMENT ON PROCEDURE public.foo >> IS 'Foo procedure'; >> ----- >> >> ----- >> 2016-03-23 11:22:02,186: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >> 11:22:02] "GET /browser/procedure/obj/1/2/14844/13627/16387 HTTP/1.1" >> 500 - >> Traceback (most recent call last): >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1836, in __call__ >> return self.wsgi_app(environ, start_response) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1820, in wsgi_app >> response = self.make_response(self.handle_exception(e)) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1403, in handle_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1817, in wsgi_app >> response = self.full_dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1477, in full_dispatch_request >> rv = self.handle_user_exception(e) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1381, in handle_user_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1475, in full_dispatch_request >> rv = self.dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1461, in dispatch_request >> return self.view_functions[rule.endpoint](**req.view_args) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", >> line 84, in view >> return self.dispatch_request(*args, **kwargs) >> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line >> 233, in dispatch_request >> return method(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 349, in wrap >> return f(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 425, in properties >> resp_data = self._fetch_properties(gid, sid, did, scid, fnid) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 1097, in _fetch_properties >> resp_data = res['rows'][0] >> IndexError: list index out of range >> ----- >> >> - After a Python server reset, I get the following error when trying >> to view SQL of a Procedure (seems like it thinks it's connected to >> PG?): >> >> TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql >> 2016-03-23 11:28:52,852: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >> 11:28:52] "GET /browser/procedure/nodes/1/2/14844/2200/ HTTP/1.1" 500 >> - >> Traceback (most recent call last): >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1836, in __call__ >> return self.wsgi_app(environ, start_response) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1820, in wsgi_app >> response = self.make_response(self.handle_exception(e)) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1403, in handle_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1817, in wsgi_app >> response = self.full_dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1477, in full_dispatch_request >> rv = self.handle_user_exception(e) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1381, in handle_user_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1475, in full_dispatch_request >> rv = self.dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1461, in dispatch_request >> return self.view_functions[rule.endpoint](**req.view_args) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", >> line 84, in view >> return self.dispatch_request(*args, **kwargs) >> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line >> 233, in dispatch_request >> return method(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 349, in wrap >> return f(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 390, in nodes >> 'node.sql']), scid=scid) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", >> line 127, in render_template >> return >> _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >> line 830, in get_or_select_template >> return self.get_template(template_name_or_list, parent, globals) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >> line 791, in get_template >> return self._load_template(name, self.make_globals(globals)) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >> line 765, in _load_template >> template = self.loader.load(self, name, globals) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/loaders.py", >> line 113, in load >> source, filename, uptodate = self.get_source(environment, name) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", >> line 64, in get_source >> raise TemplateNotFound(template) >> TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql >> 2016-03-23 11:28:57,953: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >> 11:28:57] "POST /ping HTTP/1.1" 200 - >> >> - Procedures do not include the schema name in the headers of reverse >> engineered SQL, e.g. >> >> - What's the trailing - in the parameter list in this reverse engineered >> SQL? >> >> -- PROCEDURE: foo >> >> -- DROP PROCEDURE foo; >> >> CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT >> b integer DEFAULT -) >> VOLATILE NOT LEAKPROOF SECURITY DEFINER >> COST 100.0 >> AS >> >> BEGIN >> b:=a+b+1; >> END; >> >> COMMENT ON PROCEDURE public.foo >> IS 'Foo procedure'; >> >> Thanks! >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company > > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [application/octet-stream] pgAdmin4_function_ver1-dave.patch (229.9K, 2-pgAdmin4_function_ver1-dave.patch) download | inline diff: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py new file mode 100644 index 0000000..25bb07e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py @@ -0,0 +1,1295 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements Functions/Procedures Node.""" + +import json +import sys +import traceback +import copy +import re +from flask import render_template, make_response, request, jsonify, \ + current_app, url_for +from flask.ext.babel import gettext +from functools import wraps +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases.schemas as schemas +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ + parse_priv_to_db +from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ + SchemaChildModule, DataTypeReader +from config import PG_DEFAULT_DRIVER +from pgadmin.browser.server_groups.servers.databases.utils import \ + parse_sec_labels_from_db, parse_variables_from_db + +class FunctionModule(SchemaChildModule): + """ + class FunctionModule(SchemaChildModule): + + This class represents The Functions Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Functions Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Functions collection node. + + * node_inode(): + - Returns Functions node as leaf node. + + * script_load() + - Load the module script for Functions, when schema node is + initialized. + + * csssnippets() + - Returns a snippet of css. + """ + + NODE_TYPE = 'function' + COLLECTION_LABEL = gettext("Functions") + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(FunctionModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Functions collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Functions, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css + """ + snippets = [ + render_template("function/css/function.css") + ] + snippets.extend( + super(SchemaChildModule, self).csssnippets + ) + + return snippets + +blueprint = FunctionModule(__name__) + + +class FunctionView(PGChildNodeView, DataTypeReader): + """ + class FunctionView(PGChildNodeView) + + This class inherits PGChildNodeView to get the different routes for + the module. + + The class is responsible to Create, Read, Update and Delete operations for + the Functions. + + Methods: + ------- + * validate_request(f): + - Works as a decorator. + Validating request on the request of create, update and modified SQL. + + * module_js(): + - Overrides this property to define javascript for Functions node. + + * check_precondition(f): + - Works as a decorator. + - Checks database connection status. + - Attach connection object and template path. + + * list(gid, sid, did, scid): + - List the Functions. + + * nodes(gid, sid, did, scid): + - Returns all the Functions to generate Nodes in the browser. + + * properties(gid, sid, did, scid, fnid): + - Returns the Functions properties. + + * create(gid, sid, did, scid): + - Creates a new Functions object. + + * update(gid, sid, did, scid, fnid): + - Updates the Functions object. + + * delete(gid, sid, did, scid, fnid): + - Drops the Functions object. + + * sql(gid, sid, did, scid, fnid): + - Returns the SQL for the Functions object. + + * msql(gid, sid, did, scid, fnid=None): + - Returns the modified SQL. + + * dependents(gid, sid, did, scid, fnid): + - Returns the dependents for the Functions object. + + * dependencies(gid, sid, did, scid, fnid): + - Returns the dependencies for the Functions object. + + * get_languages(gid, sid, did, scid, fnid=None): + - Returns languages. + + * types(gid, sid, did, scid, fnid=None): + - Returns Data Types. + """ + + node_type = 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': 'fnid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'delete': [{'delete': 'delete'}], + 'children': [{'get': 'children'}], + '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'}], + 'get_types': [{'get': 'types'}, {'get': 'types'}], + 'get_languages': [{'get': 'get_languages'}, {'get': 'get_languages'}], + 'vopts': [{}, {'get': 'variable_options'}] + }) + + @property + def required_args(self): + """ + Returns Required arguments for functions node. + Where + Required Args: + name: Name of the Function + funcowner: Function Owner + pronamespace: Function Namespace + prorettypename: Function Return Type + lanname: Function Language Name + prosrc: Function Code + probin: Function Object File + """ + return [ + 'name', + 'funcowner', + 'pronamespace', + 'prorettypename', + 'lanname', + 'prosrc', + 'probin' + ] + + def validate_request(f): + """ + Works as a decorator. + Validating request on the request of create, update and modified SQL. + """ + + @wraps(f) + def wrap(self, **kwargs): + + data = {} + if request.data: + req = json.loads(request.data.decode()) + else: + req = request.args or request.form + + if 'fnid' not in kwargs: + + for arg in self.required_args: + if (arg not in req or req[arg] == '') or\ + (arg == 'probin' and req['lanname'] == 'c' + and (arg not in req or req[arg] == '')): + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter \ + (%s)." % arg + ) + ) + + try: + list_params = [] + if request.method == 'GET': + list_params = ['arguments', 'variables', 'proacl', + 'seclabels', 'acl'] + + for key in req: + if key in list_params and req[key] != '' \ + and req[key] is not None: + # Coverts string into python list as expected. + data[key] = json.loads(req[key]) + elif ( + key == 'proretset' or key == 'proisstrict' or + key == 'prosecdef' or key == 'proiswindow' or + key == 'proleakproof' + ): + data[key] = True if ( + req[key] == 'true' or req[key] is True)\ + else False if (req[key] == 'false' or + req[key] is False) else '' + else: + data[key] = req[key] + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + self.request = data + return f(self, **kwargs) + + return wrap + + def module_js(self): + """ + Load JS file (functions.js) for this module. + """ + + return make_response( + render_template( + "function/js/functions.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + Works as a decorator. + Checks the database connection status. + Attaches the connection object and template path to the class object. + """ + + @wraps(f) + def wrap(*args, **kwargs): + self = args[0] + driver = get_driver(PG_DEFAULT_DRIVER) + self.manager = driver.connection_manager(kwargs['sid']) + + # Get database connection + self.conn = self.manager.connection(did=kwargs['did']) + + self.qtIdent = driver.qtIdent + self.qtLiteral = driver.qtLiteral + + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + ver = self.manager.version + + # Set template path for sql scripts depending + # on the server version. + self.template_path = "/".join([ + self.node_type + ]) + self.sql_template_path = "/".join([ + self.template_path, + self.manager.server_type, + 'sql', + '9.5_plus' if ver >= 90500 else + '9.2_plus' if ver >= 90200 else + '9.1_plus' + ]) + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + """ + List all the Functions. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + SQL = render_template("/".join([self.sql_template_path, 'node.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): + """ + Returns all the Functions to generate the Nodes. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + res = [] + SQL = render_template("/".join([self.sql_template_path, + 'node.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-" + self.node_type, + funcowner=row['funcowner'], + language=row['lanname'] + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, fnid=None): + """ + Returns the Function properties. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + return ajax_response( + response=resp_data, + status=200 + ) + + def _format_arguments_from_db(self, data): + """ + Create Argument list of the Function. + + Args: + data: Function Data + + Returns: + Function Arguments in the following format. + [ + {'proargtypes': 'integer', 'proargmodes: 'IN', + 'proargnames': 'column1', 'proargdefaultvals': 1}, {...} + ] + Where + Arguments: + proargtypes: Argument Types (Data Type) + proargmodes: Argument Modes [IN, OUT, INOUT, VARIADIC] + proargnames: Argument Name + proargdefaultvals: Default Value of the Argument + """ + proargtypes = [ptype for ptype in data['proargtypenames'].split(",")]\ + if data['proargtypenames'] else [] + proargmodes = data['proargmodes'] if data['proargmodes'] else [] + proargnames = data['proargnames'] if data['proargnames'] else [] + proargdefaultvals = [ptype for ptype in + data['proargdefaultvals'].split(",")] \ + if data['proargdefaultvals'] else [] + proallargtypes = data['proallargtypes'] \ + if data['proallargtypes'] else [] + + proargout = [] + proargid = [] + proargmodenames = {'i': 'IN', 'o': 'OUT', 'b': 'INOUT', + 'v': 'VARIADIC', 't': 'TABLE'} + + # The proargtypes doesn't give OUT params, so we need to fetch + # those from database explicitly, below code is written for this + # purpose. + # + # proallargtypes gives all the Function's argument including OUT, + # but we have not used that column; as the data type of this + # column (i.e. oid[]) is not supported by oidvectortypes(oidvector) + # function which we have used to fetch the datatypes + # of the other parameters. + + proargmodes_fltrd = copy.deepcopy(proargmodes) + proargnames_fltrd = [] + cnt = 0 + for m in proargmodes: + if m == 'o': # Out Mode + SQL = render_template("/".join([self.sql_template_path, + 'get_out_types.sql']), + out_arg_oid=proallargtypes[cnt]) + status, out_arg_type = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=out_arg_type) + + # Insert out parameter datatype + proargtypes.insert(cnt, out_arg_type) + proargdefaultvals.insert(cnt, '') + elif m == 'v': # Variadic Mode + proargdefaultvals.insert(cnt, '') + elif m == 't': # Table Mode + proargmodes_fltrd.remove(m) + proargnames_fltrd.append(proargnames[cnt]) + + cnt += 1 + + cnt = 0 + # Map param's short form to its actual name. (ex: 'i' to 'IN') + for m in proargmodes_fltrd: + proargmodes_fltrd[cnt] = proargmodenames[m] + cnt += 1 + + # Removes Argument Names from the list if that argument is removed + # from the list + for i in proargnames_fltrd: + proargnames.remove(i) + + # Insert null value against the parameters which do not have + # default values. + if len(proargmodes_fltrd) > len(proargdefaultvals): + dif = len(proargmodes_fltrd) - len(proargdefaultvals) + while (dif > 0): + proargdefaultvals.insert(0, '') + dif = dif - 1 + + # Prepare list of Argument list dict to be displayed in the Data Grid. + params = {"arguments": [ + self._map_arguments_dict( + i, proargmodes_fltrd[i] if len(proargmodes_fltrd) > i else '', + proargtypes[i] if len(proargtypes) > i else '', + proargnames[i] if len(proargnames) > i else '', + proargdefaultvals[i] if len(proargdefaultvals) > i else '' + ) + for i in range(len(proargtypes))]} + + # Prepare string formatted Argument to be displayed in the Properties + # panel. + + proargs = [self._map_arguments_list( + proargmodes_fltrd[i] if len(proargmodes_fltrd) > i else '', + proargtypes[i] if len(proargtypes) > i else '', + proargnames[i] if len(proargnames) > i else '', + proargdefaultvals[i] if len(proargdefaultvals) > i else '' + ) + for i in range(len(proargtypes))] + + proargs = {"proargs": ", ".join(proargs)} + + return params, proargs + + def _map_arguments_dict(self, argid, argmode, argtype, argname, argdefval): + """ + Returns Dict of formatted Arguments. + Args: + argid: Argument Sequence Number + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + return {"argid": argid, + "argtype": argtype.strip() if argtype is not None else '', + "argmode": argmode, + "argname": argname, + "argdefval": argdefval} + + def _map_arguments_list(self, argmode, argtype, argname, argdef): + """ + Returns List of formatted Arguments. + Args: + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + arg = '' + + if argmode: + arg += argmode + " " + if argname: + arg += argname + " " + if argtype: + arg += argtype + " " + if argdef: + arg += " DEFAULT " + argdef + + return arg + + def _format_proacl_from_db(self, proacl): + """ + Returns privileges. + Args: + proacl: Privileges Dict + """ + privileges = [] + for row in proacl: + priv = parse_priv_from_db(row) + privileges.append(priv) + + return {"acl": privileges} + + @check_precondition + def types(self, gid, sid, did, scid, fnid=None): + """ + Returns the Data Types. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + condition = "(typtype IN ('b', 'c', 'd', 'e', 'p', 'r') AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger'))" + if self.blueprint.show_system_objects: + condition += " AND nspname NOT LIKE E'pg\\\\_toast%' AND nspname NOT LIKE E'pg\\\\_temp%'" + + # Get Types + status, types = self.get_types(self.conn, condition) + + if not status: + return internal_server_error(errormsg=types) + + return make_json_response( + data=types, + status=200 + ) + + @check_precondition + def get_languages(self, gid, sid, did, scid, fnid=None): + """ + Returns the Languages list. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_languages.sql']) + ) + status, rows = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res + rows['rows'] + + return make_json_response( + data=res, + status=200 + ) + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + current_app.logger.error(traceback.print_exception( + exc_type, + exc_value, + exc_traceback, + limit=2 + ) + ) + + return internal_server_error(errormsg=str(exc_value)) + + @check_precondition + def variable_options(self, gid, sid, did, scid, fnid=None): + """ + Returns the variables. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + This function will return list of variables available for + table spaces. + """ + SQL = render_template( + "/".join([self.sql_template_path, 'variables.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=rset) + + return make_json_response( + data=rset['rows'], + status=200 + ) + + @check_precondition + @validate_request + def create(self, gid, sid, did, scid): + """ + Create a new Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + Function object in json format. + """ + + try: + # Get SQL to create Function + status, SQL = self._get_sql(gid, sid, did, scid, self.request) + if not status: + return internal_server_error(errormsg=SQL) + + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join([self.sql_template_path, + 'get_oid.sql']), + nspname=self.request['pronamespace'], + name=self.request['name']) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res['rows'][0] + + return jsonify( + node=self.blueprint.generate_browser_node( + res['oid'], + self.request['pronamespace'], + res['name'], + icon="icon-" + self.node_type, + language=res['lanname'], + funcowner=res['funcowner'] + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, fnid): + """ + Drop the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Fetch Name and Schema Name to delete the Function. + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), scid=scid, fnid=fnid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + name, func_args, nspname = res['rows'][0] + + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), + name=name, + func_args=func_args, + nspname=nspname, + 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("Function Dropped."), + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + @validate_request + def update(self, gid, sid, did, scid, fnid): + """ + Update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + + if not status: + return internal_server_error(errormsg=SQL) + + 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) + + return make_json_response( + success=1, + info="Function Updated.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, fnid=None): + """ + Returns the SQL for the Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.node_type == 'procedure': + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get SQL to create Function + status, func_def = self._get_sql(gid, sid, did, scid, resp_data, + None, True) + if not status: + return internal_server_error(errormsg=func_def) + + name = resp_data['name'] + else: + # Fetch the function definition. + SQL = render_template("/".join([self.sql_template_path, + 'get_definition.sql']), fnid=fnid, scid=scid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + func_def, name = res['rows'][0] + + sql_header = """-- {0}: {1} + +-- DROP {0} {1}; + +""".format(self.node_type.upper(), name) + + SQL = sql_header + func_def + + return ajax_response(response=SQL) + + @check_precondition + @validate_request + def msql(self, gid, sid, did, scid, fnid=None): + """ + Returns the modified SQL. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + Returns: + SQL statements to create/update the Domain. + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + if status: + return make_json_response( + data=SQL, + status=200 + ) + else: + return SQL + + def _get_sql(self, gid, sid, did, scid, data, fnid=None, is_sql=False): + """ + Generates the SQL statements to create/update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + data: Function data + fnid: Function Id + """ + + try: + vol_dict = {'v': 'VOLATILE', 's': 'STABLE', 'i': 'IMMUTABLE'} + + # Get Schema Name from its OID. + if 'pronamespace' in data: + data['pronamespace'] = self._get_schema(data[ + 'pronamespace']) + if 'provolatile' in data: + data['provolatile'] = vol_dict[data['provolatile']] + + if fnid is not None: + # Edit Mode + + # Fetch Old Data from database. + old_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get Schema Name + old_data['pronamespace'] = self._get_schema(old_data[ + 'pronamespace']) + + if 'provolatile' in old_data: + old_data['provolatile'] = vol_dict[old_data['provolatile']] + + # If any of the below argument is changed, + # then CREATE OR REPLACE SQL statement should be called + fun_change_args = ['lanname', 'prosrc', 'probin', 'prosrc_c', + 'provolatile', 'proisstrict', 'prosecdef', + 'procost', 'proleakproof', 'arguments'] + + data['change_func'] = False + for arg in fun_change_args: + if arg == 'arguments' and arg in data and len(data[arg]) \ + > 0: + data['change_func'] = True + elif arg in data: + data['change_func'] = True + + # If Function Definition/Arguments are changed then merge old + # Arguments with changed ones for Create/Replace Function + # SQL statement + if 'arguments' in data and len(data['arguments']) > 0: + for arg in data['arguments']['changed']: + for old_arg in old_data['arguments']: + if arg['argid'] == old_arg['argid']: + old_arg.update(arg) + break + data['arguments'] = old_data['arguments'] + elif data['change_func']: + data['arguments'] = old_data['arguments'] + + # Parse Privileges + if 'acl' in data: + for key in ['added', 'deleted', 'changed']: + if key in data['acl']: + data['acl'][key] = parse_priv_to_db( + data['acl'][key], ["X"]) + + # Parse Variables + chngd_variables = {} + data['merged_variables'] = [] + old_data['chngd_variables'] = {} + del_variables = {} + + # If Function Definition/Arguments are changed then, + # Merge old, new (added, changed, deleted) variables, + # which will be used in the CREATE or REPLACE Function sql + # statement + + if data['change_func']: + # To compare old and new variables, preparing name : + # value dict + + # Deleted Variables + if 'variables' in data and 'deleted' in data['variables']: + for v in data['variables']['deleted']: + del_variables[v['name']] = v['value'] + + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + chngd_variables[v['name']] = v['value'] + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + chngd_variables[v['name']] = v['value'] + + for v in old_data['variables']: + old_data['chngd_variables'][v['name']] = v['value'] + + # Prepare final dict of new and old variables + for name, val in old_data['chngd_variables'].items(): + if name not in chngd_variables and name not in \ + del_variables: + chngd_variables[name] = val + + # Prepare dict in [{'name': var_name, 'value': var_val},..] + # format + for name, val in chngd_variables.items(): + data['merged_variables'].append({'name': name, + 'value': val}) + else: + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + data['merged_variables'].append(v) + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + data['merged_variables'].append(v) + + SQL = render_template( + "/".join([self.sql_template_path, 'update.sql']), + data=data, o_data=old_data + ) + else: + # Parse Privileges + if 'acl' in data: + data['acl'] = parse_priv_to_db(data['acl'], ["X"]) + + args = '' + cnt = 1 + if 'arguments' in data: + for a in data['arguments']: + if (('argmode' in a and a['argmode'] != 'OUT' and + a['argmode'] is not None + ) or 'argnode' not in a): + if 'argmode' in a: + args += a['argmode'] + " " + if 'argname' in a and a['argname'] != ''\ + and a['argname'] is not None: + args += self.qtIdent( + self.conn, a['argname']) + " " + if 'argtype' in a: + args += a['argtype'] + if cnt < len(data['arguments']): + args += ', ' + cnt += 1 + + data['func_args'] = args.strip(' ') + # Create mode + SQL = render_template("/".join([self.sql_template_path, + 'create.sql']), + data=data, is_sql=is_sql) + return True, SQL.strip('\n') + + except Exception as e: + return False, e + + def _fetch_properties(self, gid, sid, did, scid, fnid=None): + """ + Return Function Properties which will be used in properties, + msql function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = {} + + SQL = render_template("/".join([self.sql_template_path, + 'properties.sql']), + scid=scid, fnid=fnid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + resp_data = res['rows'][0] + + # Get formatted Arguments + frmtd_params, frmtd_proargs = self._format_arguments_from_db(resp_data) + resp_data.update(frmtd_params) + resp_data.update(frmtd_proargs) + + # Fetch privileges + SQL = render_template("/".join([self.sql_template_path, 'acl.sql']), + fnid=fnid) + status, proaclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Get Formatted Privileges + resp_data.update(self._format_proacl_from_db(proaclres['rows'])) + + # Set System Functions Status + resp_data['sysfunc'] = False + if fnid <= self.manager.db_info[did]['datlastsysoid']: + resp_data['sysfunc'] = True + + # Get formatted Security Labels + if 'seclabels' in resp_data: + resp_data.update(parse_sec_labels_from_db(resp_data['seclabels'])) + + # Get formatted Variable + resp_data.update(parse_variables_from_db([ + {"setconfig": resp_data['proconfig']}])) + + return resp_data + + def _get_schema(self, scid): + """ + Returns Schema Name from its OID. + + Args: + scid: Schema Id + """ + SQL = render_template("/".join([self.sql_template_path, + '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 dependents(self, gid, sid, did, scid, fnid): + """ + This function get the dependents and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependents_result = self.get_dependents(self.conn, fnid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, fnid): + """ + This function get the dependencies and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependencies_result = self.get_dependencies(self.conn, fnid) + return ajax_response( + response=dependencies_result, + status=200 + ) + +FunctionView.register_node_view(blueprint) + + +class ProcedureModule(SchemaChildModule): + """ + class ProcedureModule(SchemaChildModule): + + This class represents The Procedures Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Procedures Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Procedures collection node. + + * node_inode(): + - Returns Procedures node as leaf node. + + * script_load() + - Load the module script for Procedures, when schema node is + initialized. + + """ + + NODE_TYPE = 'procedure' + COLLECTION_LABEL = gettext("Procedures") + + def __init__(self, *args, **kwargs): + """ + Initialize the Procedure Module. + Args: + *args: + **kwargs: + """ + super(ProcedureModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = ['ppas'] + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Procedures collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Procedures, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + +procedure_blueprint = ProcedureModule(__name__) + + +class ProcedureView(FunctionView): + + node_type = procedure_blueprint.node_type + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(ProcedureView, self).__init__(*args, **kwargs) + + @property + def required_args(self): + """ + Returns Required arguments for procedures node. + Where + Required Args: + name: Name of the Function + pronamespace: Function Namespace + lanname: Function Language Name + prosrc: Function Code + """ + return ['name', + 'pronamespace', + 'lanname', + 'prosrc'] + + def module_js(self): + """ + Load JS file (procedures.js) for this module. + """ + + return make_response( + render_template( + "procedure/js/procedures.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + +ProcedureView.register_node_view(procedure_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png new file mode 100644 index 0000000000000000000000000000000000000000..c44874e5574e624c2687689ac75f3ba4ed69e811 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE0CVL=8;#?*`-(h^sRi9 z*>&~c)34PF?}pc0oO}FT&eYpg3!lCJ{{QpuKPl}Gawb0N+VtXry&)e^8)He3UoeBi zvm0qZ4rhT!WHFHT0Ash4*>*riqNj^vh{WaCes{hD1{^FOt?qvPzrI(~vFzEgEEaCT zKn8&fCc|T@oHyDw|30!InX~Vp=DDQ@|E}SiWNDf1d5o{vOS9^<jH6JQ%!{XA68~=T zUVHU-(WR)_zZZZ1_xt(xjh~rXW-{}Bc$;4hv`n?cHKHUXu_V<hxhNG#F&G&b8tNJt z>Kd7b7@Arcm|Gc`Y8#kY85l5Do_~m<AvZrIGp!P&!9dr*5~wG{$k@un#LB=-+W@H3 U;MDZcH9!pvp00i_>zopr06KSqcmMzZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..7c13a9bc73a782b5139095af596e15d7b68dd20c GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9EC%sCbm^nUN&dsC)d z%g%m(?%cJOmUB^2&)2TKR$To5`}b?r)x6ex&wxr9OM?7@862M7NCR>>3p^r=fwTu0 zyPeFo12PglT^vI=t|uoXgaoB9FsmgiGa57px_XMbaBFHxO0zOZW@WzA@{)3Bd#1Ev zf>nS=wRyl)0gsIDYK$8M1T>mj(wGjaEU<j_)L{XKVdhn(2@iX`tkM;(8Sb=j%x%8O z&&KdzmZ)RwGzMRwWvV5v5hW>!C8<`)MX5lF!N|bSP}jgv*T^))(A3Jn+{)NY+rZ4q zz+j);rTHita`RI%(<(t440H`FfqFuWjIB&etPFq}fI1CMO%GiI)WG2B>gTe~DWM4f DC&Fq! literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png new file mode 100644 index 0000000000000000000000000000000000000000..656854a0191b5dd5d465f90cfbceebdc3913f1a2 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF3h)VW1=3U3Jn||!yY$MRhadm{ z{r~UY=bu~de4cgqZS9ih={*lqIv$kGe$v0=Wy+ox+kmPWOM?7@862M7NCR>>3p^r= zfwTu0yPeFo12Td<T^vI=t|uorFgbMz%nH2e!Eh#_sIZa4a8(-{W2?l}DN`<8YH;#- zst}-Z;J_6|HZC3?W5<L^3=wBng(l?o+}ds4$eUzU%$C*nPL(la_XP%qilxGbk7sB! z0Zmseag8WRNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KrrHLkRt5(1-s!DE(U6;; ll9^Ts(O_T+)&Nv(Vr5_k(Qs;d=o+8~22WQ%mvv4FO#sGkaAg1h literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..8b65dff9eb2c373df031669adba7a82c0ae2aaa6 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9Cs%{mqo^m6CUA1_|~ z|NHmbqerjy?R&Ir+0E|mOJ!vji;J%}H<uLMy$n>!SQ6wH%;50sMjDXAS>O>_45U54 z*zIJt9gq>^>Eal|aXmS~fyt>$U{>Hw4~8=dMTLzVhO64x7+WQ#PMLD)QiGGvQ-uJP z0|%}!vT^bF7&|6RVu(1qDl{Rt=hklXM&2Z=Vz#WlMH3iS#bz)t#6K1K?su<o8qjpr z64!{5l*E!$tK_0oAjM#0U}&goV5n<k8e(W_WngY)Y^H5sW@TWoPwvuu6b-rgDVb@N pAPok(29`iQAx6elCMH$}Kn*~h2B)Tnt^sOb@O1TaS?83{1OQh#ZFT?v literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css new file mode 100644 index 0000000..16b2e71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css @@ -0,0 +1,3 @@ +.functions_code { + height: 130px !important; +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js new file mode 100644 index 0000000..a596147 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js @@ -0,0 +1,441 @@ +/* Create and Register Function Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.browser.collection', 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-function']) { + var functions = pgAdmin.Browser.Nodes['coll-function'] = + pgAdmin.Browser.Collection.extend({ + node: 'function', + label: '{{ _('Functions') }}', + type: 'coll-function', + columns: ['name', 'funcowner', 'description'] + }); + }; + + // Security Model + var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({ + defaults: { + provider: null, + label: null + }, + schema: [{ + id: 'provider', label: '{{ _('Provider') }}', + type: 'text', editable: true, cellHeaderClasses:'width_percent_50' + },{ + id: 'security_label', label: '{{ _('Security Label') }}', + type: 'text', editable: true, cellHeaderClasses:'width_percent_50' + }], + validate: function() { + var err = {}, + errmsg = null, + data = this.toJSON(); + + if (_.isUndefined(data.label) || + _.isNull(data.label) || + String(data.label).replace(/^\s+|\s+$/g, '') == '') { + return _("Please specify the value for all the security providers."); + } + return null; + } + }); + + // Argument Model + var ArgumentModel = pgAdmin.Browser.Node.Model.extend({ + idAttribute: 'argid', + defaults: { + argid: undefined, + argtype: undefined, + argmode: undefined, + argname: undefined, + argdefval: undefined + }, + schema: [{ + id: 'argid', visible: false, type: 'text', + mode: ['properties', 'edit','create'] + },{ + id: 'argtype', label:'{{ _('Data Type') }}', cell: + 'node-ajax-options', cellHeaderClasses: 'width_percent_30', + control: 'node-ajax-options', type: 'text', url: 'get_types', + editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + }, first_empty: true + },{ + id: 'argmode', label:'{{ _('Mode') }}', type: 'options', + control: 'node-ajax-options', cellHeaderClasses:'width_percent_20', + options:[ + {'label': 'IN', 'value': 'IN'}, + {'label': 'OUT', 'value': 'OUT'}, + {'label': 'INOUT', 'value': 'INOUT'}, + {'label': 'VARIADIC', 'value': 'VARIADIC'} + ], editable: function(m) { + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argname', label:'{{ _('Argument Name') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_30', + },{ + id: 'argdefval', label:'{{ _('Default Value') }}', type: 'text', + cell: 'string', editable: true, cellHeaderClasses:'width_percent_20' + } + ], + toJSON: Backbone.Model.prototype.toJSON + }); + + if (!pgBrowser.Nodes['function']) { + pgAdmin.Browser.Nodes['function'] = pgBrowser.Node.extend({ + type: 'function', + label: '{{ _('Function') }}', + collection_type: 'coll-function', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function(args) { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + pgBrowser.add_menus([{ + name: 'create_function_on_coll', node: 'coll-function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: false}, + enable: 'canCreate' + } + ]); + + }, + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + schema_id = args.node_info.schema._id + this.set({'pronamespace': schema_id}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'funcowner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + defaults: { + name: undefined, + oid: undefined, + xmin: undefined, + funcowner: undefined, + pronamespace: undefined, + description: undefined, + pronargs: undefined, /* Argument Count */ + proargs: undefined, /* Arguments */ + proargtypenames: undefined, /* Argument Signature */ + prorettypename: undefined, /* Return Type */ + lanname: 'sql', /* Language Name in which function is being written */ + provolatile: undefined, /* Volatility */ + proretset: undefined, /* Return Set */ + proisstrict: undefined, + prosecdef: undefined, /* Security of definer */ + proiswindow: undefined, /* Window Function ? */ + procost: undefined, /* Estimated execution Cost */ + prorows: undefined, /* Estimated number of rows */ + proleakproof: undefined, + arguments: [], + prosrc: undefined, + prosrc_c: undefined, + probin: '$libdir/', + options: [], + variables: [], + proacl: undefined, + seclabels: [], + acl: [], + sysfunc: undefined + }, + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'] + },{ + id: 'oid', label: '{{ _('OID') }}', cell: 'string', + type: 'text' , mode: ['properties'] + },{ + id: 'funcowner', label: '{{ _('Owner') }}', cell: 'string', + control: Backform.NodeListByNameControl, node: 'role', type: + 'text', disabled: 'isDisabled' + },{ + id: 'pronamespace', label: '{{ _('Schema') }}', cell: 'string', + control: 'node-list-by-id', type: 'text', cache_level: 'database', + node: 'schema', mode: ['create', 'edit'] + },{ + id: 'sysfunc', label: '{{ _('System function?') }}', + cell:'boolean', type: 'switch', + mode: ['properties'] + },{ + id: 'description', label: '{{ _('Comment') }}', cell: 'string', + type: 'multiline' + },{ + id: 'pronargs', label: '{{ _('Argument count') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties'] + },{ + id: 'proargs', label: '{{ _('Arguments') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties', 'edit'], + disabled: 'isDisabled' + },{ + id: 'proargtypenames', label: '{{ _('Signature arguments') }}', cell: + 'string', type: 'text', group: '{{ _('Definition') }}', mode: ['properties'], + disabled: 'isDisabled' + },{ + id: 'prorettypename', label: '{{ _('Return type') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_types', disabled: 'isDisabled', first_empty: true, + mode: ['create'] + },{ + id: 'prorettypename', label: '{{ _('Return type') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: true, + mode: ['properties', 'edit'] + }, { + id: 'lanname', label: '{{ _('Language') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_languages', disabled: 'isDisabled' + },{ + id: 'prosrc', label:'{{ _("Code") }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}', + control: Backform.SqlFieldControl, extraClasses:['custom_height_css_class'], visible: + function(m) { + if (m.get('lanname') == 'c') { return false; } + return true; + }, + },{ + id: 'probin', label: '{{ _('Object File') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'prosrc_c', label: '{{ _('Link Symbol') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + } + },{ + id: 'provolatile', label: '{{ _('Volatility') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Options') }}', + options:[ + {'label': 'VOLATILE', 'value': 'v'}, + {'label': 'STABLE', 'value': 's'}, + {'label': 'IMMUTABLE', 'value': 'i'}, + ], disabled: 'isDisabled' + },{ + id: 'proretset', label: '{{ _('Returns a set?') }}', group: '{{ _('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled' + },{ + id: 'proisstrict', label: '{{ _('Strict?') }}', group: '{{ _ + ('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled', options: { + 'onText': 'Yes', 'offText': 'No', + 'onColor': 'success', 'offColor': 'primary', + 'size': 'small' + } + },{ + id: 'prosecdef', label: '{{ _('Security of definer?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'proiswindow', label: '{{ _('Window?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'procost', label: '{{ _('Estimated cost') }}', group: '{{ _('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled' + },{ + id: 'prorows', label: '{{ _('Estimated rows') }}', group: '{{ _ + ('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled', + deps: ['proretset'] + },{ + id: 'proleakproof', label: '{{ _('Leak proof?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', min_version: 90200, + disabled: 'isDisabled' + },{ + id: 'proacl', label: '{{ _('Privileges') }}', + group: '{{ _('Security') }}', cell:'boolean', type: 'text', cell: 'string', + mode: ['properties'] + },{ + id: 'arguments', label: '{{ _('Parameters') }}', cell: 'string', + group: '{{ _('Parameters') }}', type: 'collection', canAdd: function(m){ + return m.isNew(); + }, + canDelete: true, model: ArgumentModel, mode: + ['create', 'edit'], editable: false, + columns: ['argtype', 'argmode', 'argname', 'argdefval'] + },{ + id: 'variables', label: '{{ _('Variables') }}', type: 'collection', + group: '{{ _('Variables') }}', control: 'variable-collection', + model: pgAdmin.Browser.Node.VariableModel, + mode: ['edit', 'create'], canAdd: 'canVarAdd', canEdit: false, + canDelete: true, disabled: 'isDisabled' + },{ + id: 'acl', label: '{{ _('Privileges') }}', model: pgAdmin + .Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['X']}), uniqueCol : ['grantee', 'grantor'], + editable: false, type: 'collection', group: '{{ _('Security') }}', + mode: ['edit', 'create'], + canAdd: true, canDelete: true, control: 'unique-col-collection', + }, + { + id: 'seclabels', label: '{{ _('Security Labels') }}', + model: SecurityModel, type: 'collection', + group: '{{ _('Security') }}', mode: ['edit', 'create'], + min_version: 90100, canAdd: true, + canEdit: true, canDelete: true, + control: 'unique-col-collection', uniqueCol : ['provider'] + } + ], + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('funcowner')) || String(this.get('funcowner')).replace(/^\s+|\s+$/g, '') == '') { + err['funcowner'] = '{{ _('Owner can not be empty!') }}'; + errmsg = errmsg || err['funcowner']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('prorettypename')) || String(this.get('prorettypename')).replace(/^\s+|\s+$/g, '') == '') { + err['prorettypename'] = '{{ _('Return Type can not be empty!') }}'; + errmsg = errmsg || err['prorettypename']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (String(this.get('lanname')) == 'c') { + if (_.isUndefined(this.get('probin')) || String(this.get('probin')) + .replace(/^\s+|\s+$/g, '') == '') { + err['probin'] = '{{ _('Object File can not be empty!') }}'; + errmsg = errmsg || err['probin']; + } + + if (_.isUndefined(this.get('prosrc_c')) || String(this.get('prosrc_c')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc_c'] = '{{ _('Link Symbol can not be empty!') }}'; + errmsg = errmsg || err['prosrc_c']; + } + } + else { + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + } + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + return null; + }, + isDisabled: function(m){ + name = this.name; + switch(name){ + case 'proargs': + case 'proargtypenames': + case 'proretset': + case 'proiswindow': + return !m.isNew(); + break; + case 'prorows': + if(m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return false; + break; + } + }, + canVarAdd: function(m) { + return true; + } + }), + 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 Function + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-function' == d._type) { + //Check if we are not child of catalog + 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['function']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql new file mode 100644 index 0000000..7b29a3c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql @@ -0,0 +1,53 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proisstrict %}STRICT {% endif %}{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.proiswindow %}WINDOW{% endif -%}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif %}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif %} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql new file mode 100644 index 0000000..af0f28e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql @@ -0,0 +1,105 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif %}{% endif %} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif %} +{% endif %}{% endif %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql new file mode 100644 index 0000000..70a3d43 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %} LEAKPROOF {% else %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor -%} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif -%} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql new file mode 100644 index 0000000..5b60590 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql new file mode 100644 index 0000000..6bc01c2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %} LEAKPROOF {% else %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql new file mode 100644 index 0000000..28e3642 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..7b29a3c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,53 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proisstrict %}STRICT {% endif %}{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.proiswindow %}WINDOW{% endif -%}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif %}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif %} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..af0f28e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,105 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif %}{% endif %} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif %} +{% endif %}{% endif %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..70a3d43 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %} LEAKPROOF {% else %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor -%} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif -%} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..c24970c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,22 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade%} CASCADE{% +endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..5b60590 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..6bc01c2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %} LEAKPROOF {% else %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..28e3642 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js new file mode 100644 index 0000000..f50ffe9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js @@ -0,0 +1,171 @@ +/* Create and Register Procedure Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.node.function', 'pgadmin.browser.collection', + 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify, Function) { + + if (!pgBrowser.Nodes['coll-procedure']) { + var procedures = pgAdmin.Browser.Nodes['coll-procedure'] = + pgAdmin.Browser.Collection.extend({ + node: 'procedure', + label: '{{ _('Procedures') }}', + type: 'coll-procedure', + columns: ['name', 'funcowner', 'description'] + }); + }; + + pgSchemaNode = pgBrowser.Nodes['schema']; + + // Inherit Functions Node + if (!pgBrowser.Nodes['procedure']) { + pgAdmin.Browser.Nodes['procedure'] = Function.extend({ + type: 'procedure', + label: '{{ _('Procedure') }}', + collection_type: 'coll-procedure', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.proc_initialized) + return; + + this.proc_initialized = true; + + pgBrowser.add_menus([{ + name: 'create_procedure_on_coll', node: 'coll-procedure', module: + this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + false} + },{ + name: 'create_procedure', node: 'procedure', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, + },{ + name: 'create_procedure', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, enable: 'canCreateProc' + } + ]); + }, + canDrop: pgSchemaNode.canChildDrop, + canDropCascade: pgSchemaNode.canChildDrop, + model: Function.model.extend({ + defaults: _.extend({}, + Function.model.prototype.defaults, + { + lanname: 'edbspl' + } + ), + canVarAdd: function(m){ + var server = this.node_info.server; + if (server.version < 90500) { + return false; + } + else { + return true; + } + }, + isDisabled: function(m) { + name = this.name; + switch(name){ + case 'provolatility': + case 'proisstrict': + case 'prosecdef': + case 'procost': + case 'proleakproof': + case 'variables': + var server = this.node_info.server; + if (server.version < 90500) { + return true; + } + else { + return false; + } + break; + case 'prorows': + var server = this.node_info.server; + if(server.version >= 90500 && m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return true; + break; + } + }, + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + return null; + }, + } + ), + canCreateProc: function(itemData, item, data) { + var node_hierarchy = this.getTreeNodeHierarchy.apply(this, [item]); + + // Do not provide Create option in catalog + if ('catalog' in node_hierarchy) + return false; + + // Procedures supported only in PPAS + if ('server' in node_hierarchy && node_hierarchy['server'].type == "ppas") + return true; + + return false; + + } + }); + + } + + return pgBrowser.Nodes['procedure']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..942181d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,33 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..1cf2c10 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,82 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..b1ee22c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,33 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor -%}){% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..4dd4637 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,78 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} +AS {% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..fd81c66 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,43 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor -%}){% endif %} + + {{ data.provolatile }}{% if data.proleakproof %} LEAKPROOF {% elif not data.proleakproof %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..30cab8d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,19 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..dff9373 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,102 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + {% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% else %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'PROCEDURE', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'PROCEDURE', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros index 08d1198..1ac4cea 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/functions/privilege.macros @@ -1,13 +1,9 @@ {##############################################} {# Macros for Privileges (functions module) #} {##############################################} -{% macro SET(conn, type, role, param, privs, with_grant_privs, schema, func_args) -%} -{% if privs %} -GRANT {{ privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{conn|qtIdent(role) }}; -{% endif %} -{% if with_grant_privs %} -GRANT {{ with_grant_privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{ conn|qtIdent(role) }} WITH GRANT OPTION; -{% endif %} +{% macro SET(conn, type, role, param, privs, with_grant_privs, schema, func_args) -%}{% if privs %} +GRANT {{ privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{conn|qtIdent(role) }};{% endif %}{% if with_grant_privs %} +GRANT {{ with_grant_privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) TO {{ conn|qtIdent(role) }} WITH GRANT OPTION;{% endif %} {%- endmacro %} {% macro UNSETALL(conn, type, role, param, schema, func_args) -%} REVOKE ALL ON {{ type }} {{ conn|qtIdent(schema, param) }}({{func_args}}) FROM {{conn|qtIdent(role) }}; ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-03-28 07:26 Khushboo Vashi <[email protected]> parent: Dave Page <[email protected]> 1 sibling, 1 reply; 11+ messages in thread From: Khushboo Vashi @ 2016-03-28 07:26 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi, Please find updated patch for the functions/procedures module. Thanks, Khushboo On Wed, Mar 23, 2016 at 5:33 PM, Dave Page <[email protected]> wrote: > On Tue, Mar 22, 2016 at 10:51 AM, Khushboo Vashi > <[email protected]> wrote: > > Hi, > > > > Please find updated Patch for the Functions/Procedures Module. > > Hi > > Unfortunately I found more issues as I tested in-depth. I've attached > an updated patch in which I've done some cleanup - additional comments > below: > > - Some argument lists are shown with an extra space, e.g. > > character varying , integer > > (pem.create_agent(character varying , integer)) > Done > - A 404 error is seen when functions are selected under a Catalog node. > Done > - Procedures have a property of "System function?" - should be "System > procedure?" > > Done > - The Return Type, Returns a Set and Window fields should be hidden > for Procedures. > > Done > - When creating a procedure (below), I get the following error: > > ----- > -- PROCEDURE: foo > > -- DROP PROCEDURE foo; > > CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT > b integer DEFAULT -) > VOLATILE NOT LEAKPROOF SECURITY DEFINER > COST 100.0 > AS > > BEGIN > b:=a+b+1; > END; > > COMMENT ON PROCEDURE public.foo > IS 'Foo procedure'; > ----- > > ----- > 2016-03-23 11:22:02,186: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 > 11:22:02] "GET /browser/procedure/obj/1/2/14844/13627/16387 HTTP/1.1" > 500 - > Traceback (most recent call last): > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1836, in __call__ > return self.wsgi_app(environ, start_response) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1820, in wsgi_app > response = self.make_response(self.handle_exception(e)) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1403, in handle_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1817, in wsgi_app > response = self.full_dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1477, in full_dispatch_request > rv = self.handle_user_exception(e) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1381, in handle_user_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1475, in full_dispatch_request > rv = self.dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1461, in dispatch_request > return self.view_functions[rule.endpoint](**req.view_args) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", > line 84, in view > return self.dispatch_request(*args, **kwargs) > File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line > 233, in dispatch_request > return method(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 349, in wrap > return f(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 425, in properties > resp_data = self._fetch_properties(gid, sid, did, scid, fnid) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 1097, in _fetch_properties > resp_data = res['rows'][0] > IndexError: list index out of range > ----- > > - After a Python server reset, I get the following error when trying > to view SQL of a Procedure (seems like it thinks it's connected to > PG?): > > TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql > 2016-03-23 11:28:52,852: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 > 11:28:52] "GET /browser/procedure/nodes/1/2/14844/2200/ HTTP/1.1" 500 > - > Traceback (most recent call last): > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1836, in __call__ > return self.wsgi_app(environ, start_response) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1820, in wsgi_app > response = self.make_response(self.handle_exception(e)) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1403, in handle_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1817, in wsgi_app > response = self.full_dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1477, in full_dispatch_request > rv = self.handle_user_exception(e) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1381, in handle_user_exception > reraise(exc_type, exc_value, tb) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1475, in full_dispatch_request > rv = self.dispatch_request() > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", > line 1461, in dispatch_request > return self.view_functions[rule.endpoint](**req.view_args) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", > line 84, in view > return self.dispatch_request(*args, **kwargs) > File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line > 233, in dispatch_request > return method(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 349, in wrap > return f(*args, **kwargs) > File > "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", > line 390, in nodes > 'node.sql']), scid=scid) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", > line 127, in render_template > return > _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", > line 830, in get_or_select_template > return self.get_template(template_name_or_list, parent, globals) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", > line 791, in get_template > return self._load_template(name, self.make_globals(globals)) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", > line 765, in _load_template > template = self.loader.load(self, name, globals) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/loaders.py", > line 113, in load > source, filename, uptodate = self.get_source(environment, name) > File > "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", > line 64, in get_source > raise TemplateNotFound(template) > TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql > 2016-03-23 11:28:57,953: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 > 11:28:57] "POST /ping HTTP/1.1" 200 - > > Done > - Procedures do not include the schema name in the headers of reverse > engineered SQL, e.g. > > Done > - What's the trailing - in the parameter list in this reverse engineered > SQL? > > -- PROCEDURE: foo > > -- DROP PROCEDURE foo; > > CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT > b integer DEFAULT -) > VOLATILE NOT LEAKPROOF SECURITY DEFINER > COST 100.0 > AS > > BEGIN > b:=a+b+1; > END; > > COMMENT ON PROCEDURE public.foo > IS 'Foo procedure'; > > Done > Thanks! > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] pgAdmin4_function_ver2.patch (232.2K, 3-pgAdmin4_function_ver2.patch) download | inline diff: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py new file mode 100644 index 0000000..8e6947f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py @@ -0,0 +1,1314 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements Functions/Procedures Node.""" + +import json +import sys +import traceback +import copy +import re +from flask import render_template, make_response, request, jsonify, \ + current_app, url_for +from flask.ext.babel import gettext +from functools import wraps +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error, gone +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases.schemas as schemas +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ + parse_priv_to_db +from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ + SchemaChildModule, DataTypeReader +from config import PG_DEFAULT_DRIVER +from pgadmin.browser.server_groups.servers.databases.utils import \ + parse_sec_labels_from_db, parse_variables_from_db + +class FunctionModule(SchemaChildModule): + """ + class FunctionModule(SchemaChildModule): + + This class represents The Functions Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Functions Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Functions collection node. + + * node_inode(): + - Returns Functions node as leaf node. + + * script_load() + - Load the module script for Functions, when schema node is + initialized. + + * csssnippets() + - Returns a snippet of css. + """ + + NODE_TYPE = 'function' + COLLECTION_LABEL = gettext("Functions") + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(FunctionModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Functions collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Functions, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css + """ + snippets = [ + render_template("function/css/function.css") + ] + snippets.extend( + super(SchemaChildModule, self).csssnippets + ) + + return snippets + +blueprint = FunctionModule(__name__) + + +class FunctionView(PGChildNodeView, DataTypeReader): + """ + class FunctionView(PGChildNodeView) + + This class inherits PGChildNodeView to get the different routes for + the module. + + The class is responsible to Create, Read, Update and Delete operations for + the Functions. + + Methods: + ------- + * validate_request(f): + - Works as a decorator. + Validating request on the request of create, update and modified SQL. + + * module_js(): + - Overrides this property to define javascript for Functions node. + + * check_precondition(f): + - Works as a decorator. + - Checks database connection status. + - Attach connection object and template path. + + * list(gid, sid, did, scid): + - List the Functions. + + * nodes(gid, sid, did, scid): + - Returns all the Functions to generate Nodes in the browser. + + * properties(gid, sid, did, scid, fnid): + - Returns the Functions properties. + + * create(gid, sid, did, scid): + - Creates a new Functions object. + + * update(gid, sid, did, scid, fnid): + - Updates the Functions object. + + * delete(gid, sid, did, scid, fnid): + - Drops the Functions object. + + * sql(gid, sid, did, scid, fnid): + - Returns the SQL for the Functions object. + + * msql(gid, sid, did, scid, fnid=None): + - Returns the modified SQL. + + * dependents(gid, sid, did, scid, fnid): + - Returns the dependents for the Functions object. + + * dependencies(gid, sid, did, scid, fnid): + - Returns the dependencies for the Functions object. + + * get_languages(gid, sid, did, scid, fnid=None): + - Returns languages. + + * types(gid, sid, did, scid, fnid=None): + - Returns Data Types. + """ + + node_type = 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': 'fnid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'delete': [{'delete': 'delete'}], + 'children': [{'get': 'children'}], + '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'}], + 'get_types': [{'get': 'types'}, {'get': 'types'}], + 'get_languages': [{'get': 'get_languages'}, {'get': 'get_languages'}], + 'vopts': [{}, {'get': 'variable_options'}] + }) + + @property + def required_args(self): + """ + Returns Required arguments for functions node. + Where + Required Args: + name: Name of the Function + funcowner: Function Owner + pronamespace: Function Namespace + prorettypename: Function Return Type + lanname: Function Language Name + prosrc: Function Code + probin: Function Object File + """ + return [ + 'name', + 'funcowner', + 'pronamespace', + 'prorettypename', + 'lanname', + 'prosrc', + 'probin' + ] + + def validate_request(f): + """ + Works as a decorator. + Validating request on the request of create, update and modified SQL. + """ + + @wraps(f) + def wrap(self, **kwargs): + + data = {} + if request.data: + req = json.loads(request.data.decode()) + else: + req = request.args or request.form + + if 'fnid' not in kwargs: + + for arg in self.required_args: + if (arg not in req or req[arg] == '') or\ + (arg == 'probin' and req['lanname'] == 'c' + and (arg not in req or req[arg] == '')): + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter \ + (%s)." % arg + ) + ) + + try: + list_params = [] + if request.method == 'GET': + list_params = ['arguments', 'variables', 'proacl', + 'seclabels', 'acl'] + + for key in req: + if key in list_params and req[key] != '' \ + and req[key] is not None: + # Coverts string into python list as expected. + data[key] = json.loads(req[key]) + elif ( + key == 'proretset' or key == 'proisstrict' or + key == 'prosecdef' or key == 'proiswindow' or + key == 'proleakproof' + ): + data[key] = True if ( + req[key] == 'true' or req[key] is True)\ + else False if (req[key] == 'false' or + req[key] is False) else '' + else: + data[key] = req[key] + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + self.request = data + return f(self, **kwargs) + + return wrap + + def module_js(self): + """ + Load JS file (functions.js) for this module. + """ + + return make_response( + render_template( + "function/js/functions.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + Works as a decorator. + Checks the database connection status. + Attaches the connection object and template path to the class object. + """ + + @wraps(f) + def wrap(*args, **kwargs): + self = args[0] + driver = get_driver(PG_DEFAULT_DRIVER) + self.manager = driver.connection_manager(kwargs['sid']) + + # Get database connection + self.conn = self.manager.connection(did=kwargs['did']) + + self.qtIdent = driver.qtIdent + self.qtLiteral = driver.qtLiteral + + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + ver = self.manager.version + + # Set template path for sql scripts depending + # on the server version. + self.template_path = "/".join([ + self.node_type + ]) + self.sql_template_path = "/".join([ + self.template_path, + self.manager.server_type, + 'sql', + '9.5_plus' if ver >= 90500 else + '9.2_plus' if ver >= 90200 else + '9.1_plus' + ]) + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + """ + List all the Functions. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + SQL = render_template("/".join([self.sql_template_path, 'node.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): + """ + Returns all the Functions to generate the Nodes. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + """ + + res = [] + SQL = render_template("/".join([self.sql_template_path, + 'node.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-" + self.node_type, + funcowner=row['funcowner'], + language=row['lanname'] + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, fnid=None): + """ + Returns the Function properties. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + return ajax_response( + response=resp_data, + status=200 + ) + + def _format_arguments_from_db(self, data): + """ + Create Argument list of the Function. + + Args: + data: Function Data + + Returns: + Function Arguments in the following format. + [ + {'proargtypes': 'integer', 'proargmodes: 'IN', + 'proargnames': 'column1', 'proargdefaultvals': 1}, {...} + ] + Where + Arguments: + proargtypes: Argument Types (Data Type) + proargmodes: Argument Modes [IN, OUT, INOUT, VARIADIC] + proargnames: Argument Name + proargdefaultvals: Default Value of the Argument + """ + proargtypes = [ptype for ptype in data['proargtypenames'].split(",")]\ + if data['proargtypenames'] else [] + proargmodes = data['proargmodes'] if data['proargmodes'] else [] + proargnames = data['proargnames'] if data['proargnames'] else [] + proargdefaultvals = [ptype for ptype in + data['proargdefaultvals'].split(",")] \ + if data['proargdefaultvals'] else [] + proallargtypes = data['proallargtypes'] \ + if data['proallargtypes'] else [] + + proargout = [] + proargid = [] + proargmodenames = {'i': 'IN', 'o': 'OUT', 'b': 'INOUT', + 'v': 'VARIADIC', 't': 'TABLE'} + + # The proargtypes doesn't give OUT params, so we need to fetch + # those from database explicitly, below code is written for this + # purpose. + # + # proallargtypes gives all the Function's argument including OUT, + # but we have not used that column; as the data type of this + # column (i.e. oid[]) is not supported by oidvectortypes(oidvector) + # function which we have used to fetch the datatypes + # of the other parameters. + + proargmodes_fltrd = copy.deepcopy(proargmodes) + proargnames_fltrd = [] + cnt = 0 + for m in proargmodes: + if m == 'o': # Out Mode + SQL = render_template("/".join([self.sql_template_path, + 'get_out_types.sql']), + out_arg_oid=proallargtypes[cnt]) + status, out_arg_type = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=out_arg_type) + + # Insert out parameter datatype + proargtypes.insert(cnt, out_arg_type) + proargdefaultvals.insert(cnt, '') + elif m == 'v': # Variadic Mode + proargdefaultvals.insert(cnt, '') + elif m == 't': # Table Mode + proargmodes_fltrd.remove(m) + proargnames_fltrd.append(proargnames[cnt]) + + cnt += 1 + + cnt = 0 + # Map param's short form to its actual name. (ex: 'i' to 'IN') + for m in proargmodes_fltrd: + proargmodes_fltrd[cnt] = proargmodenames[m] + cnt += 1 + + # Removes Argument Names from the list if that argument is removed + # from the list + for i in proargnames_fltrd: + proargnames.remove(i) + + # Insert null value against the parameters which do not have + # default values. + if len(proargmodes_fltrd) > len(proargdefaultvals): + dif = len(proargmodes_fltrd) - len(proargdefaultvals) + while (dif > 0): + proargdefaultvals.insert(0, '') + dif = dif - 1 + + # Prepare list of Argument list dict to be displayed in the Data Grid. + params = {"arguments": [ + self._map_arguments_dict( + i, proargmodes_fltrd[i] if len(proargmodes_fltrd) > i else '', + proargtypes[i] if len(proargtypes) > i else '', + proargnames[i] if len(proargnames) > i else '', + proargdefaultvals[i] if len(proargdefaultvals) > i else '' + ) + for i in range(len(proargtypes))]} + + # Prepare string formatted Argument to be displayed in the Properties + # panel. + + proargs = [self._map_arguments_list( + proargmodes_fltrd[i] if len(proargmodes_fltrd) > i else '', + proargtypes[i] if len(proargtypes) > i else '', + proargnames[i] if len(proargnames) > i else '', + proargdefaultvals[i] if len(proargdefaultvals) > i else '' + ) + for i in range(len(proargtypes))] + + proargs = {"proargs": ", ".join(proargs)} + + return params, proargs + + def _map_arguments_dict(self, argid, argmode, argtype, argname, argdefval): + """ + Returns Dict of formatted Arguments. + Args: + argid: Argument Sequence Number + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + # The pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) SQL + # statement gives us '-' as a default value for INOUT mode. + # so, replacing it with empty string. + if argmode == 'INOUT' and argdefval.strip() == '-': + argdefval = '' + + return {"argid": argid, + "argtype": argtype.strip() if argtype is not None else '', + "argmode": argmode, + "argname": argname, + "argdefval": argdefval} + + def _map_arguments_list(self, argmode, argtype, argname, argdef): + """ + Returns List of formatted Arguments. + Args: + argmode: Argument Mode + argname: Argument Name + argtype: Argument Type + argdef: Argument Default Value + """ + # The pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) SQL + # statement gives us '-' as a default value for INOUT mode. + # so, replacing it with empty string. + if argmode == 'INOUT' and argdef.strip() == '-': + argdef = '' + + arg = '' + + if argmode and argmode: + arg += argmode + " " + if argname: + arg += argname + " " + if argtype: + arg += argtype + " " + if argdef: + arg += " DEFAULT " + argdef + + return arg.strip(" ") + + def _format_proacl_from_db(self, proacl): + """ + Returns privileges. + Args: + proacl: Privileges Dict + """ + privileges = [] + for row in proacl: + priv = parse_priv_from_db(row) + privileges.append(priv) + + return {"acl": privileges} + + @check_precondition + def types(self, gid, sid, did, scid, fnid=None): + """ + Returns the Data Types. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + condition = "(typtype IN ('b', 'c', 'd', 'e', 'p', 'r') AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger'))" + if self.blueprint.show_system_objects: + condition += " AND nspname NOT LIKE E'pg\\\\_toast%' AND nspname NOT LIKE E'pg\\\\_temp%'" + + # Get Types + status, types = self.get_types(self.conn, condition) + + if not status: + return internal_server_error(errormsg=types) + + return make_json_response( + data=types, + status=200 + ) + + @check_precondition + def get_languages(self, gid, sid, did, scid, fnid=None): + """ + Returns the Languages list. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.sql_template_path, + 'get_languages.sql']) + ) + status, rows = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res + rows['rows'] + + return make_json_response( + data=res, + status=200 + ) + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + current_app.logger.error(traceback.print_exception( + exc_type, + exc_value, + exc_traceback, + limit=2 + ) + ) + + return internal_server_error(errormsg=str(exc_value)) + + @check_precondition + def variable_options(self, gid, sid, did, scid, fnid=None): + """ + Returns the variables. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + This function will return list of variables available for + table spaces. + """ + SQL = render_template( + "/".join([self.sql_template_path, 'variables.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=rset) + + return make_json_response( + data=rset['rows'], + status=200 + ) + + @check_precondition + @validate_request + def create(self, gid, sid, did, scid): + """ + Create a new Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + + Returns: + Function object in json format. + """ + + try: + # Get SQL to create Function + status, SQL = self._get_sql(gid, sid, did, scid, self.request) + if not status: + return internal_server_error(errormsg=SQL) + + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + SQL = render_template("/".join([self.sql_template_path, + 'get_oid.sql']), + nspname=self.request['pronamespace'], + name=self.request['name']) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + res = res['rows'][0] + + return jsonify( + node=self.blueprint.generate_browser_node( + res['oid'], + self.request['pronamespace'], + res['name'], + icon="icon-" + self.node_type, + language=res['lanname'], + funcowner=res['funcowner'] + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, scid, fnid): + """ + Drop the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Fetch Name and Schema Name to delete the Function. + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), scid=scid, fnid=fnid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + name, func_args, nspname = res['rows'][0] + + SQL = render_template("/".join([self.sql_template_path, + 'delete.sql']), + name=name, + func_args=func_args, + nspname=nspname, + 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("Function Dropped."), + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + @validate_request + def update(self, gid, sid, did, scid, fnid): + """ + Update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + + if not status: + return internal_server_error(errormsg=SQL) + + 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) + + return make_json_response( + success=1, + info="Function Updated.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update.", + data={ + 'id': fnid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, fnid=None): + """ + Returns the SQL for the Function object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + if self.node_type == 'procedure': + resp_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get SQL to create Function + status, func_def = self._get_sql(gid, sid, did, scid, resp_data, + None, True) + if not status: + return internal_server_error(errormsg=func_def) + + name = resp_data['pronamespace'] + "." + resp_data['name_with_args'] + else: + # Fetch the function definition. + SQL = render_template("/".join([self.sql_template_path, + 'get_definition.sql']), fnid=fnid, scid=scid) + status, res = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=res) + + func_def, name = res['rows'][0] + + sql_header = """-- {0}: {1} + +-- DROP {0} {1}; + +""".format(self.node_type.upper(), name) + + SQL = sql_header + func_def + + return ajax_response(response=SQL) + + @check_precondition + @validate_request + def msql(self, gid, sid, did, scid, fnid=None): + """ + Returns the modified SQL. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + Returns: + SQL statements to create/update the Domain. + """ + + status, SQL = self._get_sql(gid, sid, did, scid, self.request, fnid) + if status: + return make_json_response( + data=SQL, + status=200 + ) + else: + return SQL + + def _get_sql(self, gid, sid, did, scid, data, fnid=None, is_sql=False): + """ + Generates the SQL statements to create/update the Function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + data: Function data + fnid: Function Id + """ + + try: + vol_dict = {'v': 'VOLATILE', 's': 'STABLE', 'i': 'IMMUTABLE'} + + # Get Schema Name from its OID. + if 'pronamespace' in data: + data['pronamespace'] = self._get_schema(data[ + 'pronamespace']) + if 'provolatile' in data: + data['provolatile'] = vol_dict[data['provolatile']] + + if fnid is not None: + # Edit Mode + + # Fetch Old Data from database. + old_data = self._fetch_properties(gid, sid, did, scid, fnid) + + # Get Schema Name + old_data['pronamespace'] = self._get_schema(old_data[ + 'pronamespace']) + + if 'provolatile' in old_data: + old_data['provolatile'] = vol_dict[old_data['provolatile']] + + # If any of the below argument is changed, + # then CREATE OR REPLACE SQL statement should be called + fun_change_args = ['lanname', 'prosrc', 'probin', 'prosrc_c', + 'provolatile', 'proisstrict', 'prosecdef', + 'procost', 'proleakproof', 'arguments'] + + data['change_func'] = False + for arg in fun_change_args: + if arg == 'arguments' and arg in data and len(data[arg]) \ + > 0: + data['change_func'] = True + elif arg in data: + data['change_func'] = True + + # If Function Definition/Arguments are changed then merge old + # Arguments with changed ones for Create/Replace Function + # SQL statement + if 'arguments' in data and len(data['arguments']) > 0: + for arg in data['arguments']['changed']: + for old_arg in old_data['arguments']: + if arg['argid'] == old_arg['argid']: + old_arg.update(arg) + break + data['arguments'] = old_data['arguments'] + elif data['change_func']: + data['arguments'] = old_data['arguments'] + + # Parse Privileges + if 'acl' in data: + for key in ['added', 'deleted', 'changed']: + if key in data['acl']: + data['acl'][key] = parse_priv_to_db( + data['acl'][key], ["X"]) + + # Parse Variables + chngd_variables = {} + data['merged_variables'] = [] + old_data['chngd_variables'] = {} + del_variables = {} + + # If Function Definition/Arguments are changed then, + # Merge old, new (added, changed, deleted) variables, + # which will be used in the CREATE or REPLACE Function sql + # statement + + if data['change_func']: + # To compare old and new variables, preparing name : + # value dict + + # Deleted Variables + if 'variables' in data and 'deleted' in data['variables']: + for v in data['variables']['deleted']: + del_variables[v['name']] = v['value'] + + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + chngd_variables[v['name']] = v['value'] + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + chngd_variables[v['name']] = v['value'] + + for v in old_data['variables']: + old_data['chngd_variables'][v['name']] = v['value'] + + # Prepare final dict of new and old variables + for name, val in old_data['chngd_variables'].items(): + if name not in chngd_variables and name not in \ + del_variables: + chngd_variables[name] = val + + # Prepare dict in [{'name': var_name, 'value': var_val},..] + # format + for name, val in chngd_variables.items(): + data['merged_variables'].append({'name': name, + 'value': val}) + else: + if 'variables' in data and 'changed' in data['variables']: + for v in data['variables']['changed']: + data['merged_variables'].append(v) + + if 'variables' in data and 'added' in data['variables']: + for v in data['variables']['added']: + data['merged_variables'].append(v) + + SQL = render_template( + "/".join([self.sql_template_path, 'update.sql']), + data=data, o_data=old_data + ) + else: + # Parse Privileges + if 'acl' in data: + data['acl'] = parse_priv_to_db(data['acl'], ["X"]) + + args = '' + cnt = 1 + if 'arguments' in data: + for a in data['arguments']: + if (('argmode' in a and a['argmode'] != 'OUT' and + a['argmode'] is not None + ) or 'argnode' not in a): + if 'argmode' in a: + args += a['argmode'] + " " + if 'argname' in a and a['argname'] != ''\ + and a['argname'] is not None: + args += self.qtIdent( + self.conn, a['argname']) + " " + if 'argtype' in a: + args += a['argtype'] + if cnt < len(data['arguments']): + args += ', ' + cnt += 1 + + data['func_args'] = args.strip(' ') + # Create mode + SQL = render_template("/".join([self.sql_template_path, + 'create.sql']), + data=data, is_sql=is_sql) + return True, SQL.strip('\n') + + except Exception as e: + return False, e + + def _fetch_properties(self, gid, sid, did, scid, fnid=None): + """ + Return Function Properties which will be used in properties, + msql function. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + fnid: Function Id + """ + + resp_data = {} + + SQL = render_template("/".join([self.sql_template_path, + 'properties.sql']), + scid=scid, fnid=fnid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + if len(res['rows']) == 0: + return gone(gettext(""" +Could not find the function in the database. +It may have been removed by another user or +created/shifted to the another schema. +""")) + + resp_data = res['rows'][0] + + # Get formatted Arguments + frmtd_params, frmtd_proargs = self._format_arguments_from_db(resp_data) + resp_data.update(frmtd_params) + resp_data.update(frmtd_proargs) + + # Fetch privileges + SQL = render_template("/".join([self.sql_template_path, 'acl.sql']), + fnid=fnid) + status, proaclres = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Get Formatted Privileges + resp_data.update(self._format_proacl_from_db(proaclres['rows'])) + + # Set System Functions Status + resp_data['sysfunc'] = False + if fnid <= self.manager.db_info[did]['datlastsysoid']: + resp_data['sysfunc'] = True + + # Get formatted Security Labels + if 'seclabels' in resp_data: + resp_data.update(parse_sec_labels_from_db(resp_data['seclabels'])) + + # Get formatted Variable + resp_data.update(parse_variables_from_db([ + {"setconfig": resp_data['proconfig']}])) + + return resp_data + + def _get_schema(self, scid): + """ + Returns Schema Name from its OID. + + Args: + scid: Schema Id + """ + SQL = render_template("/".join([self.sql_template_path, + '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 dependents(self, gid, sid, did, scid, fnid): + """ + This function get the dependents and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependents_result = self.get_dependents(self.conn, fnid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, fnid): + """ + This function get the dependencies and return ajax response + for the Function node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Function Id + """ + dependencies_result = self.get_dependencies(self.conn, fnid) + return ajax_response( + response=dependencies_result, + status=200 + ) + +FunctionView.register_node_view(blueprint) + + +class ProcedureModule(SchemaChildModule): + """ + class ProcedureModule(SchemaChildModule): + + This class represents The Procedures Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Procedures Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Procedures collection node. + + * node_inode(): + - Returns Procedures node as leaf node. + + * script_load() + - Load the module script for Procedures, when schema node is + initialized. + + """ + + NODE_TYPE = 'procedure' + COLLECTION_LABEL = gettext("Procedures") + + def __init__(self, *args, **kwargs): + """ + Initialize the Procedure Module. + Args: + *args: + **kwargs: + """ + super(ProcedureModule, self).__init__(*args, **kwargs) + + self.min_ver = 90100 + self.max_ver = None + self.server_type = ['ppas'] + + def get_nodes(self, gid, sid, did, scid): + """ + Generate Procedures collection node. + """ + yield self.generate_browser_collection_node(scid) + + @property + def node_inode(self): + """ + Make the node as leaf node. + Returns: + False as this node doesn't have child nodes. + """ + return False + + @property + def script_load(self): + """ + Load the module script for Procedures, when the + schema node is initialized. + """ + return schemas.SchemaModule.NODE_TYPE + + +procedure_blueprint = ProcedureModule(__name__) + + +class ProcedureView(FunctionView): + + node_type = procedure_blueprint.node_type + + def __init__(self, *args, **kwargs): + """ + Initialize the Function Module. + Args: + *args: + **kwargs: + """ + super(ProcedureView, self).__init__(*args, **kwargs) + + @property + def required_args(self): + """ + Returns Required arguments for procedures node. + Where + Required Args: + name: Name of the Function + pronamespace: Function Namespace + lanname: Function Language Name + prosrc: Function Code + """ + return ['name', + 'pronamespace', + 'lanname', + 'prosrc'] + + def module_js(self): + """ + Load JS file (procedures.js) for this module. + """ + + return make_response( + render_template( + "procedure/js/procedures.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + +ProcedureView.register_node_view(procedure_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-function.png new file mode 100644 index 0000000000000000000000000000000000000000..c44874e5574e624c2687689ac75f3ba4ed69e811 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE0CVL=8;#?*`-(h^sRi9 z*>&~c)34PF?}pc0oO}FT&eYpg3!lCJ{{QpuKPl}Gawb0N+VtXry&)e^8)He3UoeBi zvm0qZ4rhT!WHFHT0Ash4*>*riqNj^vh{WaCes{hD1{^FOt?qvPzrI(~vFzEgEEaCT zKn8&fCc|T@oHyDw|30!InX~Vp=DDQ@|E}SiWNDf1d5o{vOS9^<jH6JQ%!{XA68~=T zUVHU-(WR)_zZZZ1_xt(xjh~rXW-{}Bc$;4hv`n?cHKHUXu_V<hxhNG#F&G&b8tNJt z>Kd7b7@Arcm|Gc`Y8#kY85l5Do_~m<AvZrIGp!P&!9dr*5~wG{$k@un#LB=-+W@H3 U;MDZcH9!pvp00i_>zopr06KSqcmMzZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/coll-procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..7c13a9bc73a782b5139095af596e15d7b68dd20c GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9EC%sCbm^nUN&dsC)d z%g%m(?%cJOmUB^2&)2TKR$To5`}b?r)x6ex&wxr9OM?7@862M7NCR>>3p^r=fwTu0 zyPeFo12PglT^vI=t|uoXgaoB9FsmgiGa57px_XMbaBFHxO0zOZW@WzA@{)3Bd#1Ev zf>nS=wRyl)0gsIDYK$8M1T>mj(wGjaEU<j_)L{XKVdhn(2@iX`tkM;(8Sb=j%x%8O z&&KdzmZ)RwGzMRwWvV5v5hW>!C8<`)MX5lF!N|bSP}jgv*T^))(A3Jn+{)NY+rZ4q zz+j);rTHita`RI%(<(t440H`FfqFuWjIB&etPFq}fI1CMO%GiI)WG2B>gTe~DWM4f DC&Fq! literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/function.png new file mode 100644 index 0000000000000000000000000000000000000000..656854a0191b5dd5d465f90cfbceebdc3913f1a2 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF3h)VW1=3U3Jn||!yY$MRhadm{ z{r~UY=bu~de4cgqZS9ih={*lqIv$kGe$v0=Wy+ox+kmPWOM?7@862M7NCR>>3p^r= zfwTu0yPeFo12Td<T^vI=t|uorFgbMz%nH2e!Eh#_sIZa4a8(-{W2?l}DN`<8YH;#- zst}-Z;J_6|HZC3?W5<L^3=wBng(l?o+}ds4$eUzU%$C*nPL(la_XP%qilxGbk7sB! z0Zmseag8WRNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KrrHLkRt5(1-s!DE(U6;; ll9^Ts(O_T+)&Nv(Vr5_k(Qs;d=o+8~22WQ%mvv4FO#sGkaAg1h literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/img/procedure.png new file mode 100644 index 0000000000000000000000000000000000000000..8b65dff9eb2c373df031669adba7a82c0ae2aaa6 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=9Cs%{mqo^m6CUA1_|~ z|NHmbqerjy?R&Ir+0E|mOJ!vji;J%}H<uLMy$n>!SQ6wH%;50sMjDXAS>O>_45U54 z*zIJt9gq>^>Eal|aXmS~fyt>$U{>Hw4~8=dMTLzVhO64x7+WQ#PMLD)QiGGvQ-uJP z0|%}!vT^bF7&|6RVu(1qDl{Rt=hklXM&2Z=Vz#WlMH3iS#bz)t#6K1K?su<o8qjpr z64!{5l*E!$tK_0oAjM#0U}&goV5n<k8e(W_WngY)Y^H5sW@TWoPwvuu6b-rgDVb@N pAPok(29`iQAx6elCMH$}Kn*~h2B)Tnt^sOb@O1TaS?83{1OQh#ZFT?v literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css new file mode 100644 index 0000000..16b2e71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/css/function.css @@ -0,0 +1,3 @@ +.functions_code { + height: 130px !important; +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js new file mode 100644 index 0000000..d62889f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/js/functions.js @@ -0,0 +1,482 @@ +/* Create and Register Function Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.browser.collection', 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-function']) { + var functions = pgAdmin.Browser.Nodes['coll-function'] = + pgAdmin.Browser.Collection.extend({ + node: 'function', + label: '{{ _('Functions') }}', + type: 'coll-function', + columns: ['name', 'funcowner', 'description'] + }); + }; + + // Security Model + var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({ + defaults: { + provider: null, + label: null + }, + schema: [{ + id: 'provider', label: '{{ _('Provider') }}', + type: 'text', editable: true, cellHeaderClasses:'width_percent_50' + },{ + id: 'security_label', label: '{{ _('Security Label') }}', + type: 'text', editable: true, cellHeaderClasses:'width_percent_50' + }], + validate: function() { + var err = {}, + errmsg = null, + data = this.toJSON(); + + if (_.isUndefined(data.label) || + _.isNull(data.label) || + String(data.label).replace(/^\s+|\s+$/g, '') == '') { + return _("Please specify the value for all the security providers."); + } + return null; + } + }); + + // Argument Model + var ArgumentModel = pgAdmin.Browser.Node.Model.extend({ + idAttribute: 'argid', + defaults: { + argid: undefined, + argtype: undefined, + argmode: undefined, + argname: undefined, + argdefval: undefined + }, + schema: [{ + id: 'argid', visible: false, type: 'text', + mode: ['properties', 'edit','create'] + },{ + id: 'argtype', label:'{{ _('Data Type') }}', cell: + 'node-ajax-options', cellHeaderClasses: 'width_percent_30', + control: 'node-ajax-options', type: 'text', url: 'get_types', + editable: function(m) { + node_info = this.get('node_info'); + if(node_info && 'catalog' in node_info) { + return false; + } + return _.isUndefined(m.isNew) ? true : m.isNew(); + }, first_empty: true + },{ + id: 'argmode', label:'{{ _('Mode') }}', type: 'options', + control: 'node-ajax-options', cellHeaderClasses:'width_percent_20', + options:[ + {'label': 'IN', 'value': 'IN'}, + {'label': 'OUT', 'value': 'OUT'}, + {'label': 'INOUT', 'value': 'INOUT'}, + {'label': 'VARIADIC', 'value': 'VARIADIC'} + ], editable: function(m) { + node_info = this.get('node_info'); + if(node_info && 'catalog' in node_info) { + return false; + } + return _.isUndefined(m.isNew) ? true : m.isNew(); + } + },{ + id: 'argname', label:'{{ _('Argument Name') }}', type: 'text', + cell: 'string', editable: 'isInCatalog', cellHeaderClasses:'width_percent_30' + },{ + id: 'argdefval', label:'{{ _('Default Value') }}', type: 'text', + cell: 'string', editable: 'isInCatalog', cellHeaderClasses:'width_percent_20' + } + ], + toJSON: Backbone.Model.prototype.toJSON, + isInCatalog: function(m){ + node_info = this.get('node_info'); + if(node_info && 'catalog' in node_info) { + return false; + } + return true; + }, + }); + + if (!pgBrowser.Nodes['function']) { + pgAdmin.Browser.Nodes['function'] = pgBrowser.Node.extend({ + type: 'function', + label: '{{ _('Function') }}', + collection_type: 'coll-function', + hasSQL: true, + hasDepends: true, + parent_type: ['schema', 'catalog'], + Init: function(args) { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + pgBrowser.add_menus([{ + name: 'create_function_on_coll', node: 'coll-function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'function', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'create_function', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Function...') }}', + icon: 'wcTabIcon icon-function', data: {action: 'create', check: false}, + enable: 'canCreate' + } + ]); + + }, + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + canDropCascade: pgBrowser.Nodes['schema'].canChildDrop, + model: pgAdmin.Browser.Node.Model.extend({ + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + // Set Selected Schema + schema_id = args.node_info.schema._id + this.set({'pronamespace': schema_id}, {silent: true}); + + // Set Current User + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + this.set({'funcowner': userInfo.name}, {silent: true}); + } + pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments); + }, + defaults: { + name: undefined, + oid: undefined, + xmin: undefined, + funcowner: undefined, + pronamespace: undefined, + description: undefined, + pronargs: undefined, /* Argument Count */ + proargs: undefined, /* Arguments */ + proargtypenames: undefined, /* Argument Signature */ + prorettypename: undefined, /* Return Type */ + lanname: 'sql', /* Language Name in which function is being written */ + provolatile: undefined, /* Volatility */ + proretset: undefined, /* Return Set */ + proisstrict: undefined, + prosecdef: undefined, /* Security of definer */ + proiswindow: undefined, /* Window Function ? */ + procost: undefined, /* Estimated execution Cost */ + prorows: undefined, /* Estimated number of rows */ + proleakproof: undefined, + arguments: [], + prosrc: undefined, + prosrc_c: undefined, + probin: '$libdir/', + options: [], + variables: [], + proacl: undefined, + seclabels: [], + acl: [], + sysfunc: undefined, + sysproc: undefined + }, + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'], + disabled: 'isDisabled' + },{ + id: 'oid', label: '{{ _('OID') }}', cell: 'string', + type: 'text' , mode: ['properties'] + },{ + id: 'funcowner', label: '{{ _('Owner') }}', cell: 'string', + control: Backform.NodeListByNameControl, node: 'role', type: + 'text', disabled: 'isDisabled' + },{ + id: 'pronamespace', label: '{{ _('Schema') }}', cell: 'string', + control: 'node-list-by-id', type: 'text', cache_level: 'database', + node: 'schema', disabled: 'isDisabled', mode: ['create', 'edit'] + },{ + id: 'sysfunc', label: '{{ _('System function?') }}', + cell:'boolean', type: 'switch', + mode: ['properties'], visible: 'isVisible' + },{ + id: 'sysproc', label: '{{ _('System procedure?') }}', + cell:'boolean', type: 'switch', + mode: ['properties'], visible: 'isVisible' + },{ + id: 'description', label: '{{ _('Comment') }}', cell: 'string', + type: 'multiline', disabled: 'isDisabled' + },{ + id: 'pronargs', label: '{{ _('Argument count') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties'] + },{ + id: 'proargs', label: '{{ _('Arguments') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', mode: ['properties', 'edit'], + disabled: 'isDisabled' + },{ + id: 'proargtypenames', label: '{{ _('Signature arguments') }}', cell: + 'string', type: 'text', group: '{{ _('Definition') }}', mode: ['properties'], + disabled: 'isDisabled' + },{ + id: 'prorettypename', label: '{{ _('Return type') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_types', disabled: 'isDisabled', first_empty: true, + mode: ['create'], visible: 'isVisible' + },{ + id: 'prorettypename', label: '{{ _('Return type') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: true, + mode: ['properties', 'edit'], disabled: 'isDisabled', visible: 'isVisible' + }, { + id: 'lanname', label: '{{ _('Language') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Definition') }}', + url: 'get_languages', disabled: 'isDisabled' + },{ + id: 'prosrc', label: '{{ _('Code') }}', cell: 'string', + type: 'text', mode: ['properties', 'create', 'edit'], + group: '{{ _('Definition') }}', deps: ['lanname'], + control: Backform.SqlFieldControl, + extraClasses:['custom_height_css_class'], + visible: function(m) { + if (m.get('lanname') == 'c') { + return false; + } + return true; + }, disabled: 'isDisabled' + },{ + id: 'probin', label: '{{ _('Object file') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + }, disabled: 'isDisabled' + },{ + id: 'prosrc_c', label: '{{ _('Link symbol') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', deps: ['lanname'], visible: + function(m) { + if (m.get('lanname') == 'c') { return true; } + return false; + }, disabled: 'isDisabled' + },{ + id: 'provolatile', label: '{{ _('Volatility') }}', cell: 'string', + control: 'node-ajax-options', type: 'text', group: '{{ _('Options') }}', + options:[ + {'label': 'VOLATILE', 'value': 'v'}, + {'label': 'STABLE', 'value': 's'}, + {'label': 'IMMUTABLE', 'value': 'i'}, + ], disabled: 'isDisabled' + },{ + id: 'proretset', label: '{{ _('Returns a set?') }}', group: '{{ _('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled', + visible: 'isVisible' + },{ + id: 'proisstrict', label: '{{ _('Strict?') }}', group: '{{ _ + ('Options') }}', + cell:'boolean', type: 'switch', disabled: 'isDisabled', + options: { + 'onText': 'Yes', 'offText': 'No', + 'onColor': 'success', 'offColor': 'primary', + 'size': 'small' + } + },{ + id: 'prosecdef', label: '{{ _('Security of definer?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled' + },{ + id: 'proiswindow', label: '{{ _('Window?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', + disabled: 'isDisabled', visible: 'isVisible' + },{ + id: 'procost', label: '{{ _('Estimated cost') }}', group: '{{ _('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled' + },{ + id: 'prorows', label: '{{ _('Estimated rows') }}', group: '{{ _ + ('Options') }}', + cell:'string', type: 'text', disabled: 'isDisabled', + deps: ['proretset'], visible: 'isVisible' + },{ + id: 'proleakproof', label: '{{ _('Leak proof?') }}', + group: '{{ _('Options') }}', cell:'boolean', type: 'switch', min_version: 90200, + disabled: 'isDisabled' + },{ + id: 'proacl', label: '{{ _('Privileges') }}', + group: '{{ _('Security') }}', cell:'boolean', type: 'text', cell: 'string', + mode: ['properties'] + },{ + id: 'arguments', label: '{{ _('Parameters') }}', cell: 'string', + group: '{{ _('Parameters') }}', type: 'collection', canAdd: function(m){ + return m.isNew(); + }, + canDelete: true, model: ArgumentModel, mode: ['create', 'edit'], + columns: ['argtype', 'argmode', 'argname', 'argdefval'], + disabled: 'isDisabled' + },{ + id: 'variables', label: '{{ _('Variables') }}', type: 'collection', + group: '{{ _('Variables') }}', control: 'variable-collection', + model: pgAdmin.Browser.Node.VariableModel, + mode: ['edit', 'create'], canAdd: 'canVarAdd', canEdit: false, + canDelete: true, disabled: 'isDisabled' + },{ + id: 'acl', label: '{{ _('Privileges') }}', model: pgAdmin + .Browser.Node.PrivilegeRoleModel.extend( + {privileges: ['X']}), uniqueCol : ['grantee', 'grantor'], + editable: false, type: 'collection', group: '{{ _('Security') }}', + mode: ['edit', 'create'], + canAdd: true, canDelete: true, control: 'unique-col-collection', + disabled: 'isDisabled' + }, + { + id: 'seclabels', label: '{{ _('Security Labels') }}', + model: SecurityModel, type: 'collection', + group: '{{ _('Security') }}', mode: ['edit', 'create'], + min_version: 90100, canAdd: true, + canEdit: true, canDelete: true, + control: 'unique-col-collection', uniqueCol : ['provider'], + disabled: 'isDisabled' + } + ], + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('funcowner')) || String(this.get('funcowner')).replace(/^\s+|\s+$/g, '') == '') { + err['funcowner'] = '{{ _('Owner can not be empty!') }}'; + errmsg = errmsg || err['funcowner']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('prorettypename')) || String(this.get('prorettypename')).replace(/^\s+|\s+$/g, '') == '') { + err['prorettypename'] = '{{ _('Return Type can not be empty!') }}'; + errmsg = errmsg || err['prorettypename']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (String(this.get('lanname')) == 'c') { + if (_.isUndefined(this.get('probin')) || String(this.get('probin')) + .replace(/^\s+|\s+$/g, '') == '') { + err['probin'] = '{{ _('Object File can not be empty!') }}'; + errmsg = errmsg || err['probin']; + } + + if (_.isUndefined(this.get('prosrc_c')) || String(this.get('prosrc_c')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc_c'] = '{{ _('Link Symbol can not be empty!') }}'; + errmsg = errmsg || err['prosrc_c']; + } + } + else { + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + } + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + return null; + }, + isVisible: function(m){ + if (this.name == 'sysproc') { return false; } + return true; + }, + isDisabled: function(m){ + if(this.node_info && 'catalog' in this.node_info) { + return true; + } + name = this.name; + switch(name){ + case 'proargs': + case 'proargtypenames': + case 'prorettypename': + case 'proretset': + case 'proiswindow': + return !m.isNew(); + break; + case 'prorows': + if(m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + default: + return false; + break; + } + return false; + }, + canVarAdd: function(m) { + if(this.node_info && 'catalog' in this.node_info) { + return false; + } + return true; + } + }), + 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 Function + if (_.indexOf(['schema'], d._type) > -1) + return true; + + if ('coll-function' == d._type) { + //Check if we are not child of catalog + 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['function']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql new file mode 100644 index 0000000..7b29a3c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/create.sql @@ -0,0 +1,53 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proisstrict %}STRICT {% endif %}{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.proiswindow %}WINDOW{% endif -%}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif %}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif %} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql new file mode 100644 index 0000000..af0f28e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/update.sql @@ -0,0 +1,105 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif %}{% endif %} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif %} +{% endif %}{% endif %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql new file mode 100644 index 0000000..50de6dc --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABLE %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor -%} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABLE.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif -%} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql new file mode 100644 index 0000000..04f8927 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql new file mode 100644 index 0000000..48a7a84 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql new file mode 100644 index 0000000..bb6ec9d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/node.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql new file mode 100644 index 0000000..51629b0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/pg/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..7b29a3c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,53 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proisstrict %}STRICT {% endif %}{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.proiswindow %}WINDOW{% endif -%}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif %}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif %} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9e8a8ba --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..af0f28e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,105 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %}{% endif %} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif %}{% endif %} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif %} +{% endif %}{% endif %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} + +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..70a3d43 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %} LEAKPROOF {% else %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor -%} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif -%} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..c24970c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,22 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade%} CASCADE{% +endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..5b60590 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} + +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames ) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..48a7a84 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,57 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data +.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} + ) + RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }} + LANGUAGE {{ data.lanname|qtLiteral }} + {% if data.provolatile %}{{ data.provolatile }} {% endif %}{% if data.proleakproof %}LEAKPROOF {% else %}NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %} +{% if data.proiswindow %}WINDOW{% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor %} +{% endif %} + +AS {% if data.lanname == 'c' %} +{{ data.probin|qtLiteral }}, {{ data.prosrc_c|qtLiteral }} +{% else %} +$function$ +{{ data.prosrc }} +$function${% endif -%}; +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{% if data.acl %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}}) + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..246bec1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..589ecce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,11 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..c7f4159 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,18 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || ')' AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '0'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..ff78298 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,31 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..28e3642 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,114 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{ +o_data.proargtypenames }}) + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %} +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %} +{% endif -%} +) + RETURNS {{ o_data.prorettypename }} +{% if 'lanname' in data %} + LANGUAGE {{ data.lanname|qtLiteral }}{% else %} + LANGUAGE {{ o_data.lanname|qtLiteral }} + {% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %} +{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} +{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} + {% endif %} + +AS {% if 'probin' in data or 'prosrc_c' in data %} +{% if 'probin' in data %}{{ data.probin|qtLiteral }}{% else %}{{ o_data.probin|qtLiteral }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral }}{% else %}{{ o_data.prosrc_c|qtLiteral }}{% endif %}{% elif 'prosrc' in data %} +$function${{ data.prosrc }}$function${% elif o_data.lanname == 'c' %} +{{ o_data.probin|qtLiteral }}, {{ o_data.prosrc_c|qtLiteral }}{% else %} +$function${{ o_data.prosrc }}$function${% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %}{% endif -%} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + IS {{ data.description|qtLiteral }}; +{% endif -%} + +{% if data.pronamespace %} + +ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }}) + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/function/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js new file mode 100644 index 0000000..e713201 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/js/procedures.js @@ -0,0 +1,184 @@ +/* Create and Register Procedure Collection and Node. */ +define( + ['jquery', 'underscore', 'underscore.string', + 'pgadmin', 'pgadmin.browser', 'alertify', + 'pgadmin.node.function', 'pgadmin.browser.collection', + 'pgadmin.browser.server.privilege'], +function($, _, S, pgAdmin, pgBrowser, alertify, Function) { + + if (!pgBrowser.Nodes['coll-procedure']) { + var procedures = pgAdmin.Browser.Nodes['coll-procedure'] = + pgAdmin.Browser.Collection.extend({ + node: 'procedure', + label: '{{ _('Procedures') }}', + type: 'coll-procedure', + columns: ['name', 'funcowner', 'description'] + }); + }; + + pgSchemaNode = pgBrowser.Nodes['schema']; + + // Inherit Functions Node + if (!pgBrowser.Nodes['procedure']) { + pgAdmin.Browser.Nodes['procedure'] = Function.extend({ + type: 'procedure', + label: '{{ _('Procedure') }}', + collection_type: 'coll-procedure', + hasSQL: true, + hasDepends: true, + parent_type: ['schema'], + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.proc_initialized) + return; + + this.proc_initialized = true; + + pgBrowser.add_menus([{ + name: 'create_procedure_on_coll', node: 'coll-procedure', module: + this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + false} + },{ + name: 'create_procedure', node: 'procedure', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, + },{ + name: 'create_procedure', node: 'schema', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Procedure...') }}', + icon: 'wcTabIcon icon-procedure', data: {action: 'create', check: + true}, enable: 'canCreateProc' + } + ]); + }, + canDrop: pgSchemaNode.canChildDrop, + canDropCascade: pgSchemaNode.canChildDrop, + model: Function.model.extend({ + defaults: _.extend({}, + Function.model.prototype.defaults, + { + lanname: 'edbspl' + } + ), + canVarAdd: function(m){ + var server = this.node_info.server; + if (server.version < 90500) { + return false; + } + else { + return true; + } + }, + isVisible: function(m){ + if (this.name == 'sysfunc') { return false; } + else if (this.name == 'sysproc') { return true; } + return false; + }, + isDisabled: function(m) { + if(this.node_info && 'catalog' in this.node_info) { + return true; + } + name = this.name; + switch(name){ + case 'provolatility': + case 'proisstrict': + case 'prosecdef': + case 'procost': + case 'proleakproof': + case 'variables': + var server = this.node_info.server; + if (server.version < 90500) { + return true; + } + else { + return false; + } + break; + case 'prorows': + var server = this.node_info.server; + if(server.version >= 90500 && m.get('proretset') == true) { + return false; + } + else { + return true; + } + break; + case 'funcowner': + case 'lanname': + case 'proargs': + return true; + default: + return false; + break; + } + return false; + }, + validate: function() + { + var err = {}, + errmsg, + seclabels = this.get('seclabels'); + + if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') { + err['name'] = '{{ _('Name can not be empty!') }}'; + errmsg = errmsg || err['name']; + } + + if (_.isUndefined(this.get('pronamespace')) || String(this.get('pronamespace')).replace(/^\s+|\s+$/g, '') == '') { + err['pronamespace'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['pronamespace']; + } + + if (_.isUndefined(this.get('lanname')) || String(this.get('lanname')).replace(/^\s+|\s+$/g, '') == '') { + err['lanname'] = '{{ _('Language can not be empty!') }}'; + errmsg = errmsg || err['lanname']; + } + + if (_.isUndefined(this.get('prosrc')) || String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') { + err['prosrc'] = '{{ _('Code can not be empty!') }}'; + errmsg = errmsg || err['prosrc']; + } + + + if (seclabels) { + var secLabelsErr; + for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) { + secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]); + if (secLabelsErr) { + err['seclabels'] = secLabelsErr; + errmsg = errmsg || secLabelsErr; + } + } + } + + this.errorModel.clear().set(err); + + return null; + }, + } + ), + canCreateProc: function(itemData, item, data) { + var node_hierarchy = this.getTreeNodeHierarchy.apply(this, [item]); + + // Do not provide Create option in catalog + if ('catalog' in node_hierarchy) + return false; + + // Procedures supported only in PPAS + if ('server' in node_hierarchy && node_hierarchy['server'].type == "ppas") + return true; + + return false; + + } + }); + + } + + return pgBrowser.Nodes['procedure']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql new file mode 100644 index 0000000..942181d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/create.sql @@ -0,0 +1,33 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %}( +{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %},{% endif %} +{% endfor %}) +{% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.label and r.provider %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql new file mode 100644 index 0000000..4b648c4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/node.sql @@ -0,0 +1,25 @@ +SELECT + pr.oid, + CASE WHEN + pg_catalog.pg_get_function_identity_arguments(pr.oid) <> '' + THEN + pr.proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')' + ELSE + pr.proname + END AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..9492f3c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/properties.sql @@ -0,0 +1,38 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (CASE WHEN + pg_catalog.pg_get_function_identity_arguments(pr.oid) <> '' + THEN + pr.proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')' + ELSE + pr.proname + END) AS name_with_args, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_seclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql new file mode 100644 index 0000000..1cf2c10 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/update.sql @@ -0,0 +1,82 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} + +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, + priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.1_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql new file mode 100644 index 0000000..b1ee22c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/create.sql @@ -0,0 +1,33 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %} {{ conn|qtIdent(p.argname)}}{% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor -%}){% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql new file mode 100644 index 0000000..4b648c4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/node.sql @@ -0,0 +1,25 @@ +SELECT + pr.oid, + CASE WHEN + pg_catalog.pg_get_function_identity_arguments(pr.oid) <> '' + THEN + pr.proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')' + ELSE + pr.proname + END AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..6cfec94 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/properties.sql @@ -0,0 +1,38 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (CASE WHEN + pg_catalog.pg_get_function_identity_arguments(pr.oid) <> '' + THEN + pr.proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')' + ELSE + pr.proname + END) AS name_with_args, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql new file mode 100644 index 0000000..4dd4637 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/update.sql @@ -0,0 +1,78 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} + +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} +AS {% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.acl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.2_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql new file mode 100644 index 0000000..ad3e0d1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/acl.sql @@ -0,0 +1,35 @@ +SELECT + COALESCE(gt.rolname, 'public') AS grantee, + g.rolname AS 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 'CONNECT' THEN 'c' + WHEN 'CREATE' THEN 'C' + WHEN 'DELETE' THEN 'd' + WHEN 'EXECUTE' THEN 'X' + WHEN 'INSERT' THEN 'a' + WHEN 'REFERENCES' THEN 'x' + WHEN 'SELECT' THEN 'r' + WHEN 'TEMPORARY' THEN 'T' + WHEN 'TRIGGER' THEN 't' + WHEN 'TRUNCATE' THEN 'D' + WHEN 'UPDATE' THEN 'w' + WHEN 'USAGE' THEN 'U' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT + (d).grantee AS grantee, (d).grantor AS grantor, + (d).is_grantable AS is_grantable, + (d).privilege_type AS privilege_type + FROM + (SELECT aclexplode(db.proacl) AS d FROM pg_proc db + WHERE db.oid = {{fnid}}::OID) 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; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql new file mode 100644 index 0000000..fd81c66 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/create.sql @@ -0,0 +1,43 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %} +{% set is_columns = [] %} +{% if data %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments %} +({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname)}} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor -%}){% endif %} + + {{ data.provolatile }}{% if data.proleakproof %} LEAKPROOF {% elif not data.proleakproof %} NOT LEAKPROOF {% endif %} +{% if data.proisstrict %}STRICT {% endif %} +{% if data.prosecdef %}SECURITY DEFINER {% endif %}{% if data.procost %} + + COST {{data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% endif -%}{% if data.variables %}{% for v in data.variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{{ data.prosrc }}; +{% if data.acl and not is_sql %} +{% for p in data.acl %} + +{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args)}} +{% endfor %}{% endif %} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }} + IS '{{ data.description }}'; +{% endif -%} +{% if data.seclabels %} +{% for r in data.seclabels %} +{% if r.security_label and r.provider %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.security_label, data.pronamespace, data.func_args) }} +{% endif %} +{% endfor %} +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql new file mode 100644 index 0000000..18701ec --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/delete.sql @@ -0,0 +1,21 @@ +{% if scid and fnid %} +SELECT + pr.proname as name, '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as func_args, + nspname +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.oid = {{fnid}}; +{% endif %} + +{% if name %} +DROP PROCEDURE {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql new file mode 100644 index 0000000..c635f1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_definition.sql @@ -0,0 +1,12 @@ +SELECT + pg_get_functiondef({{fnid}}::oid) AS func_def, + nspname || '.' || pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name +FROM + pg_proc pr +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND pr.oid = {{fnid}}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql new file mode 100644 index 0000000..f81ddfb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_languages.sql @@ -0,0 +1,4 @@ +SELECT + lanname as label, lanname as value +FROM + pg_language; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql new file mode 100644 index 0000000..2bc76a2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_oid.sql @@ -0,0 +1,17 @@ +SELECT + pr.oid, pr.proname || '(' || COALESCE(pg_catalog + .pg_get_function_identity_arguments(pr.oid), '') || ')' as name, + lanname, pg_get_userbyid(proowner) as funcowner +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +JOIN + pg_namespace nsp ON nsp.oid=pr.pronamespace + AND nsp.nspname={{ nspname|qtLiteral }} +WHERE + proisagg = FALSE + AND typname NOT IN ('trigger', 'event_trigger') + AND pr.proname = {{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql new file mode 100644 index 0000000..64a1187 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_out_types.sql @@ -0,0 +1,6 @@ +SELECT + format_type(oid, NULL) AS out_arg_type +FROM + pg_type +WHERE + oid = {{ out_arg_oid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql new file mode 100644 index 0000000..127d4b9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_schema.sql @@ -0,0 +1,6 @@ +SELECT + nspname +FROM + pg_namespace +WHERE + oid = {{ scid }}::oid; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql new file mode 100644 index 0000000..2a5582e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/get_types.sql @@ -0,0 +1,20 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND + ( + typtype IN ('b', 'c', 'd', 'e', 'p', 'r') + AND typname NOT IN ('any', 'trigger', 'language_handler', 'event_trigger') + ) + ) AS dummy +ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql new file mode 100644 index 0000000..4b648c4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/node.sql @@ -0,0 +1,25 @@ +SELECT + pr.oid, + CASE WHEN + pg_catalog.pg_get_function_identity_arguments(pr.oid) <> '' + THEN + pr.proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')' + ELSE + pr.proname + END AS name, + lanname, pg_get_userbyid(proowner) AS funcowner, description +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pr.protype = '1'::char + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql new file mode 100644 index 0000000..6cfec94 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/properties.sql @@ -0,0 +1,38 @@ +SELECT + pr.oid, pr.xmin, pr.*, pr.prosrc AS prosrc_c, + pr.proname AS name, pg_get_function_result(pr.oid) AS prorettypename, + typns.nspname AS typnsp, lanname, proargnames, oidvectortypes(proargtypes) AS proargtypenames, + pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals, + pronargdefaults, proconfig, pg_get_userbyid(proowner) AS funcowner, description, + (CASE WHEN + pg_catalog.pg_get_function_identity_arguments(pr.oid) <> '' + THEN + pr.proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')' + ELSE + pr.proname + END) AS name_with_args, + (SELECT + array_agg(provider || '=' || label) + FROM + pg_shseclabel sl1 + WHERE + sl1.objoid=pr.oid) AS seclabels +FROM + pg_proc pr +JOIN + pg_type typ ON typ.oid=prorettype +JOIN + pg_namespace typns ON typns.oid=typ.typnamespace +JOIN + pg_language lng ON lng.oid=prolang +LEFT OUTER JOIN + pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass) +WHERE + proisagg = FALSE + AND pronamespace = {{scid}}::oid + AND typname NOT IN ('trigger', 'event_trigger') +{% if fnid %} + AND pr.oid = {{fnid}}::oid +{% endif %} +ORDER BY + proname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql new file mode 100644 index 0000000..7777ccd --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/update.sql @@ -0,0 +1,102 @@ +{% import 'macros/functions/security.macros' as SECLABEL %} +{% import 'macros/functions/privilege.macros' as PRIVILEGE %} +{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %} +{% set name = o_data.name %} +{% if data.name %} +{% if data.name != o_data.name %} +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% set name = data.name %} +{% endif %} +{% endif -%} +{% if data.change_func %} +CREATE OR REPLACE PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if data.arguments %}({% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{p.argtype}}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %} +{% if not loop.last %}, {% endif %} +{% endfor %} +) +{% endif %} + {% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %}LEAKPROOF{% else %}NOT LEAKPROOF{% endif %} +{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %} +{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %} + + {% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %} + + ROWS {{data.prorows}}{% elif o_data.prorows %}ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %} + + SET {{ conn|qtIdent(v.name) }}={{ v.value|qtLiteral }}{% endfor -%} +{% endif %} + +AS +{% if data.prosrc %}{{ data.prosrc }}{% else %}{{ o_data.prosrc }}{% endif -%}; +{% endif -%} +{% if data.funcowner %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %} + OWNER TO {{ data.funcowner }}; +{% endif -%} +{# The SQL generated below will change priviledges #} +{% if data.acl %} +{% if 'deleted' in data.acl %} +{% for priv in data.acl.deleted %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in data.datacl %} +{% for priv in data.acl.changed %} + +{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in data.acl %} +{% for priv in data.acl.added %} + +{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif %} +{% endif -%} +{% if data.change_func == False %} +{% if data.variables %} +{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %} + +{{ VARIABLE.UNSET(conn, 'PROCEDURE', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% if 'merged_variables' in data and data.merged_variables|length > 0 %} + +{{ VARIABLE.SET(conn, 'PROCEDURE', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }} +{% endif -%} +{% endif -%} +{% endif -%} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} + +{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} + +{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.security_label, o_data.pronamespace, o_data.proargtypenames) }} +{% endfor %} +{% endif -%} +{% if data.description %} + +COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + IS {{ data.description|qtLiteral }}; +{% endif -%} +{% if data.pronamespace %} + +ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }} + SET SCHEMA {{ conn|qtIdent(data.pronamespace) }}; +{% endif -%} + +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql new file mode 100644 index 0000000..5233c71 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedure/ppas/sql/9.5_plus/variables.sql @@ -0,0 +1,6 @@ +SELECT + name, vartype, min_val, max_val, enumvals +FROM + pg_settings +WHERE + context in ('user', 'superuser'); ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-04-05 15:21 Dave Page <[email protected]> parent: Khushboo Vashi <[email protected]> 0 siblings, 1 reply; 11+ messages in thread From: Dave Page @ 2016-04-05 15:21 UTC (permalink / raw) To: Khushboo Vashi <[email protected]>; +Cc: pgadmin-hackers Thanks - committed. On Mon, Mar 28, 2016 at 8:26 AM, Khushboo Vashi <[email protected]> wrote: > Hi, > > Please find updated patch for the functions/procedures module. > > Thanks, > Khushboo > > On Wed, Mar 23, 2016 at 5:33 PM, Dave Page <[email protected]> wrote: >> >> On Tue, Mar 22, 2016 at 10:51 AM, Khushboo Vashi >> <[email protected]> wrote: >> > Hi, >> > >> > Please find updated Patch for the Functions/Procedures Module. >> >> Hi >> >> Unfortunately I found more issues as I tested in-depth. I've attached >> an updated patch in which I've done some cleanup - additional comments >> below: >> >> - Some argument lists are shown with an extra space, e.g. >> >> character varying , integer >> >> (pem.create_agent(character varying , integer)) > > Done >> >> - A 404 error is seen when functions are selected under a Catalog node. > > Done >> >> - Procedures have a property of "System function?" - should be "System >> procedure?" >> > Done >> >> - The Return Type, Returns a Set and Window fields should be hidden >> for Procedures. >> > Done >> >> - When creating a procedure (below), I get the following error: >> >> ----- >> -- PROCEDURE: foo >> >> -- DROP PROCEDURE foo; >> >> CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT >> b integer DEFAULT -) >> VOLATILE NOT LEAKPROOF SECURITY DEFINER >> COST 100.0 >> AS >> >> BEGIN >> b:=a+b+1; >> END; >> >> COMMENT ON PROCEDURE public.foo >> IS 'Foo procedure'; >> ----- >> >> ----- >> 2016-03-23 11:22:02,186: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >> 11:22:02] "GET /browser/procedure/obj/1/2/14844/13627/16387 HTTP/1.1" >> 500 - >> Traceback (most recent call last): >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1836, in __call__ >> return self.wsgi_app(environ, start_response) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1820, in wsgi_app >> response = self.make_response(self.handle_exception(e)) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1403, in handle_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1817, in wsgi_app >> response = self.full_dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1477, in full_dispatch_request >> rv = self.handle_user_exception(e) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1381, in handle_user_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1475, in full_dispatch_request >> rv = self.dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1461, in dispatch_request >> return self.view_functions[rule.endpoint](**req.view_args) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", >> line 84, in view >> return self.dispatch_request(*args, **kwargs) >> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line >> 233, in dispatch_request >> return method(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 349, in wrap >> return f(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 425, in properties >> resp_data = self._fetch_properties(gid, sid, did, scid, fnid) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 1097, in _fetch_properties >> resp_data = res['rows'][0] >> IndexError: list index out of range >> ----- >> >> - After a Python server reset, I get the following error when trying >> to view SQL of a Procedure (seems like it thinks it's connected to >> PG?): >> >> TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql >> 2016-03-23 11:28:52,852: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >> 11:28:52] "GET /browser/procedure/nodes/1/2/14844/2200/ HTTP/1.1" 500 >> - >> Traceback (most recent call last): >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1836, in __call__ >> return self.wsgi_app(environ, start_response) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1820, in wsgi_app >> response = self.make_response(self.handle_exception(e)) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1403, in handle_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1817, in wsgi_app >> response = self.full_dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1477, in full_dispatch_request >> rv = self.handle_user_exception(e) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1381, in handle_user_exception >> reraise(exc_type, exc_value, tb) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1475, in full_dispatch_request >> rv = self.dispatch_request() >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >> line 1461, in dispatch_request >> return self.view_functions[rule.endpoint](**req.view_args) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", >> line 84, in view >> return self.dispatch_request(*args, **kwargs) >> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line >> 233, in dispatch_request >> return method(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 349, in wrap >> return f(*args, **kwargs) >> File >> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >> line 390, in nodes >> 'node.sql']), scid=scid) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", >> line 127, in render_template >> return >> _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >> line 830, in get_or_select_template >> return self.get_template(template_name_or_list, parent, globals) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >> line 791, in get_template >> return self._load_template(name, self.make_globals(globals)) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >> line 765, in _load_template >> template = self.loader.load(self, name, globals) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/loaders.py", >> line 113, in load >> source, filename, uptodate = self.get_source(environment, name) >> File >> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", >> line 64, in get_source >> raise TemplateNotFound(template) >> TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql >> 2016-03-23 11:28:57,953: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >> 11:28:57] "POST /ping HTTP/1.1" 200 - >> > Done >> >> - Procedures do not include the schema name in the headers of reverse >> engineered SQL, e.g. >> > Done >> >> - What's the trailing - in the parameter list in this reverse engineered >> SQL? >> >> -- PROCEDURE: foo >> >> -- DROP PROCEDURE foo; >> >> CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT >> b integer DEFAULT -) >> VOLATILE NOT LEAKPROOF SECURITY DEFINER >> COST 100.0 >> AS >> >> BEGIN >> b:=a+b+1; >> END; >> >> COMMENT ON PROCEDURE public.foo >> IS 'Foo procedure'; >> > Done >> >> Thanks! >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company > > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-04-05 16:18 Thom Brown <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 11+ messages in thread From: Thom Brown @ 2016-04-05 16:18 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers I'm getting weirdness with this node. See the attached picture, where it shows the servers node appearing under functions. Thom On 5 April 2016 at 16:21, Dave Page <[email protected]> wrote: > Thanks - committed. > > On Mon, Mar 28, 2016 at 8:26 AM, Khushboo Vashi > <[email protected]> wrote: >> Hi, >> >> Please find updated patch for the functions/procedures module. >> >> Thanks, >> Khushboo >> >> On Wed, Mar 23, 2016 at 5:33 PM, Dave Page <[email protected]> wrote: >>> >>> On Tue, Mar 22, 2016 at 10:51 AM, Khushboo Vashi >>> <[email protected]> wrote: >>> > Hi, >>> > >>> > Please find updated Patch for the Functions/Procedures Module. >>> >>> Hi >>> >>> Unfortunately I found more issues as I tested in-depth. I've attached >>> an updated patch in which I've done some cleanup - additional comments >>> below: >>> >>> - Some argument lists are shown with an extra space, e.g. >>> >>> character varying , integer >>> >>> (pem.create_agent(character varying , integer)) >> >> Done >>> >>> - A 404 error is seen when functions are selected under a Catalog node. >> >> Done >>> >>> - Procedures have a property of "System function?" - should be "System >>> procedure?" >>> >> Done >>> >>> - The Return Type, Returns a Set and Window fields should be hidden >>> for Procedures. >>> >> Done >>> >>> - When creating a procedure (below), I get the following error: >>> >>> ----- >>> -- PROCEDURE: foo >>> >>> -- DROP PROCEDURE foo; >>> >>> CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT >>> b integer DEFAULT -) >>> VOLATILE NOT LEAKPROOF SECURITY DEFINER >>> COST 100.0 >>> AS >>> >>> BEGIN >>> b:=a+b+1; >>> END; >>> >>> COMMENT ON PROCEDURE public.foo >>> IS 'Foo procedure'; >>> ----- >>> >>> ----- >>> 2016-03-23 11:22:02,186: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >>> 11:22:02] "GET /browser/procedure/obj/1/2/14844/13627/16387 HTTP/1.1" >>> 500 - >>> Traceback (most recent call last): >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1836, in __call__ >>> return self.wsgi_app(environ, start_response) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1820, in wsgi_app >>> response = self.make_response(self.handle_exception(e)) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1403, in handle_exception >>> reraise(exc_type, exc_value, tb) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1817, in wsgi_app >>> response = self.full_dispatch_request() >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1477, in full_dispatch_request >>> rv = self.handle_user_exception(e) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1381, in handle_user_exception >>> reraise(exc_type, exc_value, tb) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1475, in full_dispatch_request >>> rv = self.dispatch_request() >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1461, in dispatch_request >>> return self.view_functions[rule.endpoint](**req.view_args) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", >>> line 84, in view >>> return self.dispatch_request(*args, **kwargs) >>> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line >>> 233, in dispatch_request >>> return method(*args, **kwargs) >>> File >>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >>> line 349, in wrap >>> return f(*args, **kwargs) >>> File >>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >>> line 425, in properties >>> resp_data = self._fetch_properties(gid, sid, did, scid, fnid) >>> File >>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >>> line 1097, in _fetch_properties >>> resp_data = res['rows'][0] >>> IndexError: list index out of range >>> ----- >>> >>> - After a Python server reset, I get the following error when trying >>> to view SQL of a Procedure (seems like it thinks it's connected to >>> PG?): >>> >>> TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql >>> 2016-03-23 11:28:52,852: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >>> 11:28:52] "GET /browser/procedure/nodes/1/2/14844/2200/ HTTP/1.1" 500 >>> - >>> Traceback (most recent call last): >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1836, in __call__ >>> return self.wsgi_app(environ, start_response) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1820, in wsgi_app >>> response = self.make_response(self.handle_exception(e)) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1403, in handle_exception >>> reraise(exc_type, exc_value, tb) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1817, in wsgi_app >>> response = self.full_dispatch_request() >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1477, in full_dispatch_request >>> rv = self.handle_user_exception(e) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1381, in handle_user_exception >>> reraise(exc_type, exc_value, tb) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1475, in full_dispatch_request >>> rv = self.dispatch_request() >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py", >>> line 1461, in dispatch_request >>> return self.view_functions[rule.endpoint](**req.view_args) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py", >>> line 84, in view >>> return self.dispatch_request(*args, **kwargs) >>> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line >>> 233, in dispatch_request >>> return method(*args, **kwargs) >>> File >>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >>> line 349, in wrap >>> return f(*args, **kwargs) >>> File >>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py", >>> line 390, in nodes >>> 'node.sql']), scid=scid) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", >>> line 127, in render_template >>> return >>> _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >>> line 830, in get_or_select_template >>> return self.get_template(template_name_or_list, parent, globals) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >>> line 791, in get_template >>> return self._load_template(name, self.make_globals(globals)) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/environment.py", >>> line 765, in _load_template >>> template = self.loader.load(self, name, globals) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/jinja2/loaders.py", >>> line 113, in load >>> source, filename, uptodate = self.get_source(environment, name) >>> File >>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/templating.py", >>> line 64, in get_source >>> raise TemplateNotFound(template) >>> TemplateNotFound: procedure/pg/sql/9.5_plus/node.sql >>> 2016-03-23 11:28:57,953: INFO werkzeug: 127.0.0.1 - - [23/Mar/2016 >>> 11:28:57] "POST /ping HTTP/1.1" 200 - >>> >> Done >>> >>> - Procedures do not include the schema name in the headers of reverse >>> engineered SQL, e.g. >>> >> Done >>> >>> - What's the trailing - in the parameter list in this reverse engineered >>> SQL? >>> >>> -- PROCEDURE: foo >>> >>> -- DROP PROCEDURE foo; >>> >>> CREATE OR REPLACE PROCEDURE public.foo(IN a integer DEFAULT 10, INOUT >>> b integer DEFAULT -) >>> VOLATILE NOT LEAKPROOF SECURITY DEFINER >>> COST 100.0 >>> AS >>> >>> BEGIN >>> b:=a+b+1; >>> END; >>> >>> COMMENT ON PROCEDURE public.foo >>> IS 'Foo procedure'; >>> >> Done >>> >>> Thanks! >>> >>> -- >>> Dave Page >>> Blog: http://pgsnake.blogspot.com >>> Twitter: @pgsnake >>> >>> EnterpriseDB UK: http://www.enterprisedb.com >>> The Enterprise PostgreSQL Company >> >> > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > > > -- > Sent via pgadmin-hackers mailing list ([email protected]) > To make changes to your subscription: > http://www.postgresql.org/mailpref/pgadmin-hackers -- Thom -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [image/png] Screenshot from 2016-04-05 17:16:00.png (14.3K, 2-Screenshot%20from%202016-04-05%2017:16:00.png) download | view image ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-04-05 16:20 Dave Page <[email protected]> parent: Thom Brown <[email protected]> 0 siblings, 1 reply; 11+ messages in thread From: Dave Page @ 2016-04-05 16:20 UTC (permalink / raw) To: Thom Brown <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers On Tue, Apr 5, 2016 at 5:18 PM, Thom Brown <[email protected]> wrote: > I'm getting weirdness with this node. See the attached picture, where > it shows the servers node appearing under functions. Make sure you've restarted the python server, and do a hard-refresh in your browser. That normally clears that issue up for me. -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers ^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: [pgAdmin4][Patch]: Functions/Procedures Module @ 2016-04-05 16:31 Thom Brown <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 0 replies; 11+ messages in thread From: Thom Brown @ 2016-04-05 16:31 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers On 5 April 2016 at 17:20, Dave Page <[email protected]> wrote: > On Tue, Apr 5, 2016 at 5:18 PM, Thom Brown <[email protected]> wrote: >> I'm getting weirdness with this node. See the attached picture, where >> it shows the servers node appearing under functions. > > Make sure you've restarted the python server, and do a hard-refresh in > your browser. That normally clears that issue up for me. I restarted python, but the hard refresh in the browser worked. Thanks! Thom -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers ^ permalink raw reply [nested|flat] 11+ messages in thread
end of thread, other threads:[~2016-04-05 16:31 UTC | newest] Thread overview: 11+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2016-03-11 09:34 [pgAdmin4][Patch]: Functions/Procedures Module Khushboo Vashi <[email protected]> 2016-03-11 16:47 ` Dave Page <[email protected]> 2016-03-22 10:51 ` Khushboo Vashi <[email protected]> 2016-03-23 12:03 ` Dave Page <[email protected]> 2016-03-23 13:44 ` Khushboo Vashi <[email protected]> 2016-03-23 14:01 ` Dave Page <[email protected]> 2016-03-28 07:26 ` Khushboo Vashi <[email protected]> 2016-04-05 15:21 ` Dave Page <[email protected]> 2016-04-05 16:18 ` Thom Brown <[email protected]> 2016-04-05 16:20 ` Dave Page <[email protected]> 2016-04-05 16:31 ` Thom Brown <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox