Skip to content

Commit 38ebb43

Browse files
Add support of DEPENDS/NO DEPENDS ON EXTENSION for PROCEDURE. #6391
1 parent 48b4a8d commit 38ebb43

File tree

76 files changed

+1732
-59
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1732
-59
lines changed
28 KB
Loading

docs/en_US/procedure_dialog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Use the fields in the *Definition* tab to define the procedure:
3636

3737
* Use the drop-down listbox next to *Language* to select a language. The default
3838
is *edbspl*.
39+
* Use the drop-down listbox next to *Depends on extensions* to select the extension that this procedure
40+
depends on (for example, edbspl). If set, dropping the extension will automatically drop the
41+
procedure as well.
3942
* Use the fields in the *Arguments* section to define an argument. Click *Add* to set
4043
parameters and values for the argument:
4144
* Use the drop-down listbox next to *Data type* to select a data type.

web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,10 @@ def _get_sql_for_edit_mode(self, data, parallel_dict, all_ids_dict,
11711171
old_data['proparallel'] = \
11721172
parallel_dict[old_data['proparallel']]
11731173

1174-
if self.node_type == 'function':
1174+
if self.node_type in ('function', 'procedure') and (
1175+
old_data.get('dependsonextensions') is None or
1176+
data.get('dependsonextensions') is None
1177+
):
11751178
old_data['dependsonextensions'] = \
11761179
old_data.get('dependsonextensions') or []
11771180
data['dependsonextensions'] = \

web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/function.ui.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,7 @@ export default class FunctionSchema extends BaseUISchema {
288288
placeholder: gettext('Select the Depends on extensions...'),
289289
},
290290
min_version: 130000,
291-
mode: ['create', 'edit', 'properties'],
292-
visible: obj.isVisible
291+
mode: ['create', 'edit', 'properties']
293292
},{
294293
id: 'probin', label: gettext('Object file'), cell: 'string',
295294
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:

web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/procedure.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ define('pgadmin.node.procedure', [
9292
);
9393
},
9494
getSchema: function(treeNodeInfo, itemNodeData) {
95+
let nodeObj = pgBrowser.Nodes['extension'];
9596
return new FunctionSchema(
9697
(privileges)=>getNodePrivilegeRoleSchema(this, treeNodeInfo, itemNodeData, privileges),
9798
()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, false, false),
@@ -101,6 +102,16 @@ define('pgadmin.node.procedure', [
101102
cacheLevel: 'database'
102103
}
103104
),
105+
extensionsList:()=>getNodeAjaxOptions('nodes', nodeObj, treeNodeInfo, itemNodeData, { cacheLevel: 'server'},
106+
(data)=>{
107+
let res = [];
108+
if (data && _.isArray(data)) {
109+
_.each(data, function(d) {
110+
res.push({label: d.label, value: d.label, data: d});
111+
});
112+
}
113+
return res;
114+
}),
104115
getTypes: ()=>getNodeAjaxOptions('get_types', this, treeNodeInfo, itemNodeData),
105116
getLanguage: ()=>getNodeAjaxOptions('get_languages', this, treeNodeInfo, itemNodeData),
106117
getSupportFunctions: ()=>getNodeAjaxOptions('get_support_functions', this, treeNodeInfo, itemNodeData, {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{% import 'macros/functions/security.macros' as SECLABEL %}
2+
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
3+
{% import 'macros/functions/variable.macros' as VARIABLE %}
4+
{% set is_columns = [] %}
5+
{% set exclude_quoting = ['search_path'] %}
6+
{% if data %}
7+
{% if query_for == 'sql_panel' and func_def is defined %}
8+
CREATE OR REPLACE PROCEDURE {{func_def}}
9+
{% else %}
10+
CREATE{% if add_replace_clause %} OR REPLACE{% endif %} PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}{% if data.arguments is defined %}
11+
({% 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 %}
12+
{% if not loop.last %}, {% endif %}
13+
{% endfor -%}
14+
{% endif %}
15+
)
16+
{% endif %}
17+
LANGUAGE {{ data.lanname|qtLiteral(conn) }}{% if data.prosecdef %}
18+
19+
SECURITY DEFINER {% endif %}
20+
{% if data.variables %}{% for v in data.variables %}
21+
22+
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor -%}
23+
{% endif %}
24+
25+
AS {% if data.lanname == 'c' %}
26+
{{ data.probin|qtLiteral(conn) }}, {{ data.prosrc_c|qtLiteral(conn) }}
27+
{% else %}
28+
$BODY${{ data.prosrc }}$BODY${% endif -%};
29+
30+
{% if data.funcowner %}
31+
ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
32+
OWNER TO {{ conn|qtIdent(data.funcowner) }};
33+
{% endif -%}
34+
35+
{% if data.dependsonextensions %}
36+
{% for ext in data.dependsonextensions %}
37+
38+
ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
39+
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
40+
{% endfor %}
41+
{% endif %}
42+
43+
{% if data.acl and not is_sql %}
44+
{% for p in data.acl %}
45+
46+
{{ PRIVILEGE.SET(conn, "PROCEDURE", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args_without)}}
47+
{% endfor %}{% endif %}
48+
{% if data.revoke_all %}
49+
50+
{{ PRIVILEGE.UNSETALL(conn, "PROCEDURE", "PUBLIC", data.name, data.pronamespace, data.func_args_without)}}
51+
{% endif %}
52+
{% if data.description %}
53+
54+
COMMENT ON PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
55+
IS {{ data.description|qtLiteral(conn) }};
56+
{% endif -%}
57+
{% if data.seclabels %}
58+
{% for r in data.seclabels %}
59+
{% if r.label and r.provider %}
60+
61+
{{ SECLABEL.SET(conn, 'PROCEDURE', data.name, r.provider, r.label, data.pronamespace, data.func_args_without) }}
62+
{% endif %}
63+
{% endfor %}
64+
{% endif -%}
65+
66+
{% endif %}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
SELECT
2+
pr.oid, pr.xmin,
3+
CASE WHEN pr.prokind = 'w' THEN true ELSE false END AS proiswindow,
4+
pr.prosrc, pr.prosrc AS prosrc_c, pr.pronamespace, pr.prolang, pr.procost, pr.prorows, pr.prokind,
5+
pr.prosecdef, pr.proleakproof, pr.proisstrict, pr.proretset, pr.provolatile, pr.proparallel,
6+
pr.pronargs, pr.prorettype, pr.proallargtypes, pr.proargmodes, pr.probin, pr.proacl,
7+
pr.proname, pr.proname AS name, pg_catalog.pg_get_function_result(pr.oid) AS prorettypename,
8+
typns.nspname AS typnsp, lanname, proargnames, pg_catalog.oidvectortypes(proargtypes) AS proargtypenames,
9+
pg_catalog.pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals,
10+
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
11+
(
12+
SELECT array_agg(DISTINCT e.extname)
13+
FROM pg_depend d
14+
JOIN pg_extension e ON d.refobjid = e.oid
15+
WHERE d.objid = pr.oid
16+
) AS dependsonextensions,
17+
(
18+
WITH name_with_args_tab AS (SELECT pg_catalog.pg_get_function_identity_arguments(pr.oid) AS val)
19+
SELECT CASE WHEN
20+
val <> ''
21+
THEN
22+
pr.proname || '(' || val || ')'
23+
ELSE
24+
pr.proname::text
25+
END
26+
FROM name_with_args_tab
27+
) AS name_with_args,
28+
(SELECT
29+
pg_catalog.array_agg(provider || '=' || label)
30+
FROM
31+
pg_catalog.pg_seclabel sl1
32+
WHERE
33+
sl1.objoid=pr.oid) AS seclabels
34+
FROM
35+
pg_catalog.pg_proc pr
36+
JOIN
37+
pg_catalog.pg_type typ ON typ.oid=prorettype
38+
JOIN
39+
pg_catalog.pg_namespace typns ON typns.oid=typ.typnamespace
40+
JOIN
41+
pg_catalog.pg_language lng ON lng.oid=prolang
42+
LEFT OUTER JOIN
43+
pg_catalog.pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass and des.objsubid = 0)
44+
WHERE
45+
pr.prokind = 'p'
46+
AND typname NOT IN ('trigger', 'event_trigger')
47+
{% if fnid %}
48+
AND pr.oid = {{fnid}}::oid
49+
{% else %}
50+
AND pronamespace = {{scid}}::oid
51+
{% endif %}
52+
ORDER BY
53+
proname;
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
{% import 'macros/functions/security.macros' as SECLABEL %}
2+
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
3+
{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %}
4+
{% set name = o_data.name %}
5+
{% set exclude_quoting = ['search_path'] %}
6+
{% if data.name %}
7+
{% if data.name != o_data.name %}
8+
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %}
9+
10+
RENAME TO {{ conn|qtIdent(data.name) }};
11+
{% set name = data.name %}
12+
{% endif %}
13+
14+
{% endif -%}
15+
{% if data.change_func %}
16+
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 %}
17+
{% if not loop.last %}, {% endif %}
18+
{% endfor %}
19+
{% endif %}
20+
)
21+
{% if 'lanname' in data %}
22+
LANGUAGE {{ data.lanname|qtLiteral(conn) }} {% else %}
23+
LANGUAGE {{ o_data.lanname|qtLiteral(conn) }}
24+
{% endif %}
25+
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %}SECURITY DEFINER{% endif %}
26+
{% if data.merged_variables %}{% for v in data.merged_variables %}
27+
28+
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor -%}
29+
{% endif %}
30+
31+
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
32+
{% 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 %}
33+
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
34+
{{ o_data.probin|qtLiteral(conn) }}, {{ o_data.prosrc_c|qtLiteral(conn) }}{% else %}
35+
$BODY${{ o_data.prosrc }}$BODY${% endif -%};
36+
{% endif -%}
37+
{% if data.funcowner %}
38+
39+
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}{% if o_data.proargtypenames %}({{ o_data.proargtypenames }}){% endif %}
40+
OWNER TO {{ conn|qtIdent(data.funcowner) }};
41+
{% endif -%}
42+
{# The SQL generated below will change priviledges #}
43+
{% if data.acl %}
44+
{% if 'deleted' in data.acl %}
45+
{% for priv in data.acl.deleted %}
46+
47+
{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
48+
{% endfor %}
49+
{% endif -%}
50+
{% if 'changed' in data.acl %}
51+
{% for priv in data.acl.changed %}
52+
53+
{% if priv.grantee != priv.old_grantee %}
54+
{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.old_grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
55+
{% else %}
56+
{{ PRIVILEGE.UNSETALL(conn, 'PROCEDURE', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
57+
{% endif %}
58+
59+
{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant,
60+
priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }}
61+
{% endfor %}
62+
{% endif -%}
63+
{% if 'added' in data.acl %}
64+
{% for priv in data.acl.added %}
65+
66+
{{ PRIVILEGE.SET(conn, 'PROCEDURE', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }}
67+
{% endfor %}
68+
{% endif %}
69+
{% endif -%}
70+
{% if data.change_func == False %}
71+
{% if data.variables %}
72+
{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %}
73+
74+
{{ VARIABLE.UNSET(conn, 'PROCEDURE', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }}
75+
{% endif -%}
76+
{% if 'merged_variables' in data and data.merged_variables|length > 0 %}
77+
78+
{{ VARIABLE.SET(conn, 'PROCEDURE', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }}
79+
{% endif -%}
80+
{% endif -%}
81+
{% endif -%}
82+
{% set seclabels = data.seclabels %}
83+
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
84+
{% for r in seclabels.deleted %}
85+
86+
{{ SECLABEL.UNSET(conn, 'PROCEDURE', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }}
87+
{% endfor %}
88+
{% endif -%}
89+
{% if 'added' in seclabels and seclabels.added|length > 0 %}
90+
{% for r in seclabels.added %}
91+
92+
{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.label, o_data.pronamespace, o_data.proargtypenames) }}
93+
{% endfor %}
94+
{% endif -%}
95+
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
96+
{% for r in seclabels.changed %}
97+
98+
{{ SECLABEL.SET(conn, 'PROCEDURE', name, r.provider, r.label, o_data.pronamespace, o_data.proargtypenames) }}
99+
{% endfor %}
100+
{% endif -%}
101+
{% if data.description is defined and data.description != o_data.description%}
102+
103+
COMMENT ON PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
104+
IS {{ data.description|qtLiteral(conn) }};
105+
{% endif -%}
106+
{% if data.pronamespace %}
107+
108+
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}
109+
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
110+
{% endif -%}
111+
112+
{% set old_exts = (o_data.dependsonextensions or []) | list %}
113+
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}
114+
115+
{% if new_exts is not none and old_exts != new_exts %}
116+
{% for ext in (old_exts + new_exts) | unique %}
117+
118+
{% if ext in new_exts and ext not in old_exts %}
119+
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
120+
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
121+
{% elif ext in old_exts and ext not in new_exts %}
122+
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
123+
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
124+
{% endif %}
125+
{% endfor %}
126+
{% endif %}
127+
128+
{% endif %}

web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedures/pg/sql/14_plus/create.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_arg
3535
OWNER TO {{ conn|qtIdent(data.funcowner) }};
3636
{% endif -%}
3737

38+
{% if data.dependsonextensions %}
39+
{% for ext in data.dependsonextensions %}
40+
41+
ALTER PROCEDURE {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
42+
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
43+
{% endfor %}
44+
{% endif %}
45+
3846
{% if data.acl and not is_sql %}
3947
{% for p in data.acl %}
4048

web/pgadmin/browser/server_groups/servers/databases/schemas/functions/templates/procedures/pg/sql/14_plus/properties.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ SELECT
1010
pg_catalog.pg_get_function_sqlbody(pr.oid) AS prosrc_sql,
1111
CASE WHEN pr.prosqlbody IS NOT NULL THEN true ELSE false END as is_pure_sql,
1212
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
13+
(
14+
SELECT array_agg(DISTINCT e.extname)
15+
FROM pg_depend d
16+
JOIN pg_extension e ON d.refobjid = e.oid
17+
WHERE d.objid = pr.oid
18+
) AS dependsonextensions,
1319
(
1420
WITH name_with_args_tab AS (SELECT pg_catalog.pg_get_function_identity_arguments(pr.oid) AS val)
1521
SELECT CASE WHEN

0 commit comments

Comments
 (0)