Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/en_US/images/procedure_definition.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/en_US/procedure_dialog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ Use the fields in the *Definition* tab to define the procedure:

* Use the drop-down listbox next to *Language* to select a language. The default
is *edbspl*.
* Use the drop-down listbox next to *Depends on extensions* to select the extension that this procedure
depends on (for example, edbspl). If set, dropping the extension will automatically drop the
procedure as well.
* Use the fields in the *Arguments* section to define an argument. Click *Add* to set
parameters and values for the argument:
* Use the drop-down listbox next to *Data type* to select a data type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,10 @@ def _get_sql_for_edit_mode(self, data, parallel_dict, all_ids_dict,
old_data['proparallel'] = \
parallel_dict[old_data['proparallel']]

if self.node_type == 'function':
if self.node_type in ('function', 'procedure') and (
old_data.get('dependsonextensions') is None or
data.get('dependsonextensions') is None
):
old_data['dependsonextensions'] = \
old_data.get('dependsonextensions') or []
data['dependsonextensions'] = \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,7 @@ export default class FunctionSchema extends BaseUISchema {
placeholder: gettext('Select the Depends on extensions...'),
},
min_version: 130000,
mode: ['create', 'edit', 'properties'],
visible: obj.isVisible
mode: ['create', 'edit', 'properties']
},{
id: 'probin', label: gettext('Object file'), cell: 'string',
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ define('pgadmin.node.procedure', [
);
},
getSchema: function(treeNodeInfo, itemNodeData) {
let nodeObj = pgBrowser.Nodes['extension'];
return new FunctionSchema(
(privileges)=>getNodePrivilegeRoleSchema(this, treeNodeInfo, itemNodeData, privileges),
()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, false, false),
Expand All @@ -101,6 +102,16 @@ define('pgadmin.node.procedure', [
cacheLevel: 'database'
}
),
extensionsList:()=>getNodeAjaxOptions('nodes', nodeObj, treeNodeInfo, itemNodeData, { cacheLevel: 'server'},
(data)=>{
let res = [];
if (data && _.isArray(data)) {
_.each(data, function(d) {
res.push({label: d.label, value: d.label, data: d});
});
}
return res;
}),
getTypes: ()=>getNodeAjaxOptions('get_types', this, treeNodeInfo, itemNodeData),
getLanguage: ()=>getNodeAjaxOptions('get_languages', this, treeNodeInfo, itemNodeData),
getSupportFunctions: ()=>getNodeAjaxOptions('get_support_functions', this, treeNodeInfo, itemNodeData, {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{% import 'macros/functions/security.macros' as SECLABEL %}
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
{% import 'macros/functions/variable.macros' as VARIABLE %}
{% set is_columns = [] %}
{% set exclude_quoting = ['search_path'] %}
{% if data %}
{% if query_for == 'sql_panel' and func_def is defined %}
CREATE OR REPLACE PROCEDURE {{func_def}}
{% else %}
CREATE{% if add_replace_clause %} OR REPLACE{% endif %} PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments is defined %}
({% 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 %}
)
{% endif %}
LANGUAGE {{ data.lanname|qtLiteral(conn) }}{% if data.prosecdef %}

SECURITY DEFINER {% endif %}
{% if data.variables %}{% for v in data.variables %}

SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor -%}
{% endif %}

AS {% if data.lanname == 'c' %}
{{ data.probin|qtLiteral(conn) }}, {{ data.prosrc_c|qtLiteral(conn) }}
{% else %}
$BODY${{ data.prosrc }}$BODY${% endif -%};

{% if data.funcowner %}
ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}

{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}

ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}

{% 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_without)}}
{% endfor %}{% endif %}
{% if data.revoke_all %}

{{ PRIVILEGE.UNSETALL(conn, "PROCEDURE", "PUBLIC", data.name, data.pronamespace, data.func_args_without)}}
{% endif %}
{% if data.description %}

COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
IS {{ data.description|qtLiteral(conn) }};
{% 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_without) }}
{% endif %}
{% endfor %}
{% endif -%}

{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
SELECT
pr.oid, pr.xmin,
CASE WHEN pr.prokind = 'w' THEN true ELSE false END AS proiswindow,
pr.prosrc, pr.prosrc AS prosrc_c, pr.pronamespace, pr.prolang, pr.procost, pr.prorows, pr.prokind,
pr.prosecdef, pr.proleakproof, pr.proisstrict, pr.proretset, pr.provolatile, pr.proparallel,
pr.pronargs, pr.prorettype, pr.proallargtypes, pr.proargmodes, pr.probin, pr.proacl,
pr.proname, pr.proname AS name, pg_catalog.pg_get_function_result(pr.oid) AS prorettypename,
typns.nspname AS typnsp, lanname, proargnames, pg_catalog.oidvectortypes(proargtypes) AS proargtypenames,
pg_catalog.pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals,
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = pr.oid
) AS dependsonextensions,
(
WITH name_with_args_tab AS (SELECT pg_catalog.pg_get_function_identity_arguments(pr.oid) AS val)
SELECT CASE WHEN
val <> ''
THEN
pr.proname || '(' || val || ')'
ELSE
pr.proname::text
END
FROM name_with_args_tab
) AS name_with_args,
(SELECT
pg_catalog.array_agg(provider || '=' || label)
FROM
pg_catalog.pg_seclabel sl1
WHERE
sl1.objoid=pr.oid) AS seclabels
FROM
pg_catalog.pg_proc pr
JOIN
pg_catalog.pg_type typ ON typ.oid=prorettype
JOIN
pg_catalog.pg_namespace typns ON typns.oid=typ.typnamespace
JOIN
pg_catalog.pg_language lng ON lng.oid=prolang
LEFT OUTER JOIN
pg_catalog.pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass and des.objsubid = 0)
WHERE
pr.prokind = 'p'
AND typname NOT IN ('trigger', 'event_trigger')
{% if fnid %}
AND pr.oid = {{fnid}}::oid
{% else %}
AND pronamespace = {{scid}}::oid
{% endif %}
ORDER BY
proname;
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{% 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 %}
{% set exclude_quoting = ['search_path'] %}
{% 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 'lanname' in data %}
LANGUAGE {{ data.lanname|qtLiteral(conn) }} {% else %}
LANGUAGE {{ o_data.lanname|qtLiteral(conn) }}
{% endif %}
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %}SECURITY DEFINER{% endif %}
{% if data.merged_variables %}{% for v in data.merged_variables %}

SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor -%}
{% endif %}

AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
{% if 'probin' in data %}{{ data.probin|qtLiteral(conn) }}{% else %}{{ o_data.probin|qtLiteral(conn) }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral(conn) }}{% else %}{{ o_data.prosrc_c|qtLiteral(conn) }}{% endif %}{% elif 'prosrc' in data %}
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
{{ o_data.probin|qtLiteral(conn) }}, {{ o_data.prosrc_c|qtLiteral(conn) }}{% else %}
$BODY${{ o_data.prosrc }}$BODY${% endif -%};
{% endif -%}
{% if data.funcowner %}

ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %}
OWNER TO {{ conn|qtIdent(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 %}

{% if priv.grantee != priv.old_grantee %}
{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.old_grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% else %}
{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% endif %}

{{ 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.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.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if data.description is defined and data.description != o_data.description%}

COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
IS {{ data.description|qtLiteral(conn) }};
{% endif -%}
{% if data.pronamespace %}

ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}

{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}

{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}

{% if ext in new_exts and ext not in old_exts %}
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}

{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_arg
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}

{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}

ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}

{% if data.acl and not is_sql %}
{% for p in data.acl %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ SELECT
pg_catalog.pg_get_function_sqlbody(pr.oid) AS prosrc_sql,
CASE WHEN pr.prosqlbody IS NOT NULL THEN true ELSE false END as is_pure_sql,
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = pr.oid
) AS dependsonextensions,
(
WITH name_with_args_tab AS (SELECT pg_catalog.pg_get_function_identity_arguments(pr.oid) AS val)
SELECT CASE WHEN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,20 @@ ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}

{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}

{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}

{% if ext in new_exts and ext not in old_exts %}
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}

{% endif %}
Loading
Loading