Function and procedure support for PG11. Fixes #3362

This commit is contained in:
Khushboo Vashi 2018-06-13 15:03:17 +01:00 committed by Dave Page
parent e5048b4d0b
commit d1ecba56b8
54 changed files with 1720 additions and 185 deletions

View File

@ -4,11 +4,14 @@
The Procedure Dialog
********************
Use the *Procedure* dialog to create a procedure; procedures are supported by EDB Postgres Advanced Server. The *Procedure* dialog allows you to implement options of the CREATE PROCEDURE command; for more information about the CREATE PROCEDURE SQL command, please see the Database Compatibility for Oracle Developer's, available at:
Use the *Procedure* dialog to create a procedure; procedures are supported by
PostgreSQL v11+ and EDB Postgres Advanced Server. The *Procedure* dialog allows
you to implement options of the CREATE PROCEDURE command.
http://www.enterprisedb.com
The *Procedure* dialog organizes the development of a procedure through the following dialog tabs: *General*, *Definition*, *Options*, *Arguments*, *Parameters*, and *Security*. The *SQL* tab displays the SQL code generated by dialog selections.
The *Procedure* dialog organizes the development of a procedure through the
following dialog tabs: *General*, *Definition*, *Options*, *Arguments*,
*Parameters*, and *Security*. The *SQL* tab displays the SQL code generated by
dialog selections.
.. image:: images/procedure_general.png
:alt: Procedure dialog general tab

View File

@ -10,8 +10,9 @@ This release contains a number of features and fixes reported since the release
Features
********
| `Bug #1447 <https://redmine.postgresql.org/issues/1447>`_ - Add support for SSH tunneled connections
| `Bug #3204 <https://redmine.postgresql.org/issues/3204>`_ - Add support for LISTEN/NOTIFY in the query tool
| `Feature #1447 <https://redmine.postgresql.org/issues/1447>`_ - Add support for SSH tunneled connections
| `Feature #3204 <https://redmine.postgresql.org/issues/3204>`_ - Add support for LISTEN/NOTIFY in the query tool
| `Feature #3362 <https://redmine.postgresql.org/issues/3362>`_ - Function and procedure support for PG11
Bug fixes
*********

View File

@ -1502,7 +1502,10 @@ class FunctionView(PGChildNodeView, DataTypeReader):
name = name.replace(arg, formatted_arg)
name = name.replace(')', '\n)')
sql = "EXEC {0}".format(name)
if self.manager.server_type == 'pg':
sql = "CALL {0}".format(name)
else:
sql = "EXEC {0}".format(name)
return ajax_response(response=sql)
@ -1592,10 +1595,11 @@ class ProcedureModule(SchemaChildModule):
"""
super(ProcedureModule, self).__init__(*args, **kwargs)
self.min_ver = 90100
self.min_ver = 110000
self.max_ver = None
self.min_ppasver = 90100
self.min_gpdbver = 1000000000
self.server_type = ['ppas']
self.server_type = ['pg', 'ppas']
def get_nodes(self, gid, sid, did, scid):
"""

View File

@ -71,10 +71,13 @@ define('pgadmin.node.procedure', [
if ('catalog' in node_hierarchy)
return false;
// Procedures supported only in PPAS
// Procedures supported only in PPAS and PG >= 11
return (
'server' in node_hierarchy &&
node_hierarchy['server'].server_type == 'ppas'
'server' in node_hierarchy && (
node_hierarchy['server'].server_type == 'ppas' ||
(node_hierarchy['server'].server_type == 'pg' &&
node_hierarchy['server'].version >= 110000)
)
);
},
model: Function.model.extend({
@ -103,20 +106,24 @@ define('pgadmin.node.procedure', [
return true;
}
switch(this.name){
case 'provolatility':
case 'provolatile':
case 'proisstrict':
case 'prosecdef':
case 'procost':
case 'proleakproof':
return (this.node_info.server.version < 90500 || this.node_info.server.server_type != 'ppas');
case 'variables':
case 'prosecdef':
return this.node_info.server.version < 90500;
case 'prorows':
var server = this.node_info.server;
return !(server.version >= 90500 && m.get('proretset') == true);
case 'funcowner':
case 'lanname':
case 'proargs':
return true;
case 'proparallel':
return (this.node_info.server.version < 90600 || this.node_info.server.server_type != 'ppas');
case 'lanname':
return this.node_info.server.version < 110000;
default:
return false;
}

View File

@ -0,0 +1,20 @@
SELECT
funcname AS {{ conn|qtIdent(_('Name')) }},
calls AS {{ conn|qtIdent(_('Number of calls')) }},
total_time AS {{ conn|qtIdent(_('Total time')) }},
self_time AS {{ conn|qtIdent(_('Self time')) }}
FROM
pg_stat_user_functions
WHERE
schemaname = {{schema_name|qtLiteral}}
AND funcid IN (
SELECT p.oid
FROM
pg_proc p
JOIN
pg_type typ ON typ.oid=p.prorettype
WHERE
p.prokind IN ('f', 'w')
AND typname NOT IN ('trigger', 'event_trigger')
)
ORDER BY funcname;

View File

@ -0,0 +1,70 @@
{% 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 %}
{% if query_for == 'sql_panel' and func_def is defined %}
CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} FUNCTION {{func_def}}
{% else %}
CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} 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 %}{{ conn|qtTypeIdent(p.argtype) }}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %}
{% if not loop.last %}, {% endif %}
{% endfor %}
{% endif -%}
)
{% endif %}
RETURNS{% if data.proretset and (data.prorettypename.startswith('SETOF ') or data.prorettypename.startswith('TABLE')) %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ conn|qtTypeIdent(data.prorettypename) }}{% else %} {{ conn|qtTypeIdent(data.prorettypename) }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
{% endif %}
{% if data.provolatile %}{% if data.provolatile == 'i' %}IMMUTABLE{% elif data.provolatile == 's' %}STABLE{% else %}VOLATILE{% endif %} {% endif %}{% if data.proleakproof %}LEAKPROOF {% endif %}
{% if data.proisstrict %}STRICT {% endif %}
{% if data.prosecdef %}SECURITY DEFINER {% endif %}
{% if data.proiswindow %}WINDOW {% endif %}
{% if data.proparallel and (data.proparallel == 'r' or data.proparallel == 's') %}
{% if data.proparallel == 'r' %}PARALLEL RESTRICTED{% elif data.proparallel == 's' %}PARALLEL SAFE{% endif %}{% endif -%}
{% if data.prorows and (data.prorows | int) > 0 %}
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 %}
$BODY$
{{ data.prosrc }}
$BODY${% endif -%};
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
OWNER TO {{ conn|qtIdent(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_without)}}
{% endfor %}{% endif %}
{% if data.revoke_all %}
{{ PRIVILEGE.UNSETALL(conn, "FUNCTION", "PUBLIC", data.name, data.pronamespace, data.func_args_without)}}
{% endif %}
{% if data.description %}
COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
IS {{ data.description|qtLiteral }};
{% endif -%}
{% if data.seclabels %}
{% for r in data.seclabels %}
{% if r.label and r.provider %}
{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data.pronamespace, data.func_args_without) }}
{% endif %}
{% endfor %}
{% endif -%}
{% endif %}

View File

@ -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
pr.prokind IN ('f', 'w')
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 %}

View File

@ -0,0 +1,15 @@
SELECT
pg_get_functiondef({{fnid}}::oid) AS func_def,
COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') as
func_with_identity_arguments,
nspname,
pr.proname as proname,
COALESCE(pg_catalog.pg_get_function_arguments(pr.oid), '') as func_args
FROM
pg_proc pr
JOIN
pg_namespace nsp ON nsp.oid=pr.pronamespace
WHERE
pr.prokind IN ('f', 'w')
AND pronamespace = {{scid}}::oid
AND pr.oid = {{fnid}}::oid;

View File

@ -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, pr.pronamespace as nsp
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
pr.prokind IN ('f', 'w')
AND typname NOT IN ('trigger', 'event_trigger')
AND pr.proname = {{ name|qtLiteral }};

View File

@ -0,0 +1,22 @@
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
pr.prokind IN ('f', 'w')
{% if fnid %}
AND pr.oid = {{ fnid|qtLiteral }}
{% endif %}
{% if scid %}
AND pronamespace = {{scid}}::oid
{% endif %}
AND typname NOT IN ('trigger', 'event_trigger')
ORDER BY
proname;

View File

@ -0,0 +1,33 @@
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 pr.prokind = 'w' THEN TRUE ELSE FALSE END AS proiswindow,
(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
pr.prokind IN ('f', 'w')
{% if fnid %}
AND pr.oid = {{fnid}}::oid
{% else %}
AND pronamespace = {{scid}}::oid
{% endif %}
AND typname NOT IN ('trigger', 'event_trigger')
ORDER BY
proname;

View File

@ -0,0 +1,116 @@
{% 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 %}{{ conn|qtTypeIdent(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 'proparallel' in data and data.proparallel %}PARALLEL {{ data.proparallel }}{% elif 'proparallel' not in data and o_data.proparallel %}PARALLEL {{ o_data.proparallel }}{% endif %}
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} 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 %}
$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 -%};
{% endif -%}
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
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, '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.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.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if data.description is defined and data.description != o_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 %}

View File

@ -13,7 +13,7 @@ CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} FUNCTION {{ con
{% endif -%}
)
{% endif -%}
RETURNS{% if data.proretset (data.prorettypename.startswith('SETOF ') or data.prorettypename.startswith('TABLE')) %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ conn|qtTypeIdent(data.prorettypename) }}{% else %} {{ conn|qtTypeIdent(data.prorettypename) }}{% endif %}
RETURNS{% if data.proretset and (data.prorettypename.startswith('SETOF ') or data.prorettypename.startswith('TABLE')) %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ conn|qtTypeIdent(data.prorettypename) }}{% else %} {{ conn|qtTypeIdent(data.prorettypename) }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}

View File

@ -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;

View File

@ -0,0 +1,20 @@
SELECT
funcname AS {{ conn|qtIdent(_('Name')) }},
calls AS {{ conn|qtIdent(_('Number of calls')) }},
total_time AS {{ conn|qtIdent(_('Total time')) }},
self_time AS {{ conn|qtIdent(_('Self time')) }}
FROM
pg_stat_user_functions
WHERE
schemaname = {{schema_name|qtLiteral}}
AND funcid IN (
SELECT p.oid
FROM
pg_proc p
JOIN
pg_type typ ON typ.oid=p.prorettype
WHERE
p.prokind = 'p'::char
AND typname NOT IN ('trigger', 'event_trigger')
)
ORDER BY funcname;

View File

@ -0,0 +1,50 @@
{% 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 %}
{% if query_for == 'sql_panel' and func_def is defined %}
CREATE OR REPLACE PROCEDURE {{func_def}}
{% else %}
CREATE OR REPLACE 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 %}{{ conn|qtTypeIdent(p.argtype) }}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %}
{% if not loop.last %}, {% endif %}
{% endfor -%}
{% endif %}
)
{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.prosecdef %}SECURITY DEFINER {% 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 %}
$BODY${{ data.prosrc }}$BODY${% 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) }}
IS {{ data.description|qtLiteral }};
{% 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 %}

View File

@ -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
pr.prokind = 'p'::char
AND pronamespace = {{scid}}::oid
AND typname NOT IN ('trigger', 'event_trigger')
AND pr.oid = {{fnid}};
{% endif %}
{% if name %}
DROP PROCEDURE {{ conn|qtIdent(nspname, name) }};
{% endif %}

View File

@ -0,0 +1,15 @@
SELECT
pg_get_functiondef({{fnid}}::oid) AS func_def,
COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') as
func_with_identity_arguments,
nspname,
pr.proname as proname,
COALESCE(pg_catalog.pg_get_function_arguments(pr.oid), '') as func_args
FROM
pg_proc pr
JOIN
pg_namespace nsp ON nsp.oid=pr.pronamespace
WHERE
pr.prokind = 'p'::char
AND pronamespace = {{scid}}::oid
AND pr.oid = {{fnid}}::oid;

View File

@ -0,0 +1,4 @@
SELECT
lanname as label, lanname as value
FROM
pg_language;

View File

@ -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, pr.pronamespace AS nsp
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
pr.prokind = 'p'::char
AND typname NOT IN ('trigger', 'event_trigger')
AND pr.proname = {{ name|qtLiteral }};

View File

@ -0,0 +1,6 @@
SELECT
format_type(oid, NULL) AS out_arg_type
FROM
pg_type
WHERE
oid = {{ out_arg_oid }}::oid;

View File

@ -0,0 +1,6 @@
SELECT
nspname
FROM
pg_namespace
WHERE
oid = {{ scid }}::oid;

View File

@ -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;

View File

@ -0,0 +1,29 @@
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
pr.prokind = 'p'::char
{% if fnid %}
AND pr.oid = {{ fnid|qtLiteral }}
{% endif %}
{% if scid %}
AND pronamespace = {{scid}}::oid
{% endif %}
AND typname NOT IN ('trigger', 'event_trigger')
ORDER BY
proname;

View File

@ -0,0 +1,39 @@
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
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;

View File

@ -0,0 +1,8 @@
SELECT
calls AS {{ conn|qtIdent(_('Number of calls')) }},
total_time AS {{ conn|qtIdent(_('Total time')) }},
self_time AS {{ conn|qtIdent(_('Self time')) }}
FROM
pg_stat_user_functions
WHERE
funcid = {{fnid}}::OID

View File

@ -0,0 +1,106 @@
{% 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 %}{{ conn|qtTypeIdent(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 }} {% else %}
LANGUAGE {{ o_data.lanname|qtLiteral }}
{% 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) }}={{ 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 %}
$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 -%};
{% 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, '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, '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) }}
IS {{ data.description|qtLiteral }};
{% endif -%}
{% if data.pronamespace %}
ALTER PROCEDURE {{ conn|qtIdent(o_data.pronamespace, name) }}
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}
{% endif %}

View File

@ -0,0 +1,6 @@
SELECT
name, vartype, min_val, max_val, enumvals
FROM
pg_settings
WHERE
context in ('user', 'superuser');

View File

@ -0,0 +1,20 @@
SELECT
funcname AS {{ conn|qtIdent(_('Name')) }},
calls AS {{ conn|qtIdent(_('Number of calls')) }},
total_time AS {{ conn|qtIdent(_('Total time')) }},
self_time AS {{ conn|qtIdent(_('Self time')) }}
FROM
pg_stat_user_functions
WHERE
schemaname = {{schema_name|qtLiteral}}
AND funcid IN (
SELECT p.oid
FROM
pg_proc p
JOIN
pg_type typ ON typ.oid=p.prorettype
WHERE
p.prokind IN ('f', 'w')
AND typname = 'trigger'
)
ORDER BY funcname;

View File

@ -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.proargnames %}{{data.proargnames}}{% endif %})
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
{% endif %}
{% if data.provolatile %}{% if data.provolatile == 'i' %}IMMUTABLE{% elif data.provolatile == 's' %}STABLE{% else %}VOLATILE{% endif %} {% 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.prorows and (data.prorows | int) > 0 %}
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 %}
$BODY$
{{ data.prosrc }}
$BODY${% endif -%};
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}})
OWNER TO {{ conn|qtIdent(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.revoke_all %}
{{ PRIVILEGE.UNSETALL(conn, "FUNCTION", "PUBLIC", data.name, data.pronamespace, data.func_args_without)}}
{% endif %}
{% if data.description %}
COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args}})
IS {{ data.description|qtLiteral }};
{% endif -%}
{% if data.seclabels %}
{% for r in data.seclabels %}
{% if r.label and r.provider %}
{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data.pronamespace, data.func_args) }}
{% endif %}
{% endfor %}
{% endif -%}
{% endif %}

View File

@ -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
pr.prokind IN ('f', 'w')
AND pronamespace = {{scid}}::oid
AND typname IN ('trigger', 'event_trigger')
AND pr.oid = {{fnid}};
{% endif %}
{% if name %}
DROP FUNCTION {{ conn|qtIdent(nspname, name) }}{{func_args}}{% if cascade %} CASCADE{% endif %};
{% endif %}

View File

@ -0,0 +1,15 @@
SELECT
pg_get_functiondef({{fnid}}::oid) AS func_def,
COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') as
func_with_identity_arguments,
nspname,
pr.proname as proname,
COALESCE(pg_catalog.pg_get_function_arguments(pr.oid), '') as func_args
FROM
pg_proc pr
JOIN
pg_namespace nsp ON nsp.oid=pr.pronamespace
WHERE
pr.prokind IN ('f', 'w')
AND pronamespace = {{scid}}::oid
AND pr.oid = {{fnid}}::oid;

View File

@ -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, pr.pronamespace AS nsp
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
pr.prokind IN ('f', 'w')
AND typname IN ('trigger', 'event_trigger')
AND lanname NOT IN ('edbspl', 'sql', 'internal')
AND pr.proname = {{ name|qtLiteral }};

View File

@ -0,0 +1,23 @@
SELECT
pr.oid, pr.proname || '()' 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
pr.prokind IN ('f', 'w')
{% if fnid %}
AND pr.oid = {{ fnid|qtLiteral }}
{% endif %}
{% if scid %}
AND pronamespace = {{scid}}::oid
{% endif %}
AND typname IN ('trigger', 'event_trigger')
AND lanname NOT IN ('edbspl', 'sql', 'internal')
ORDER BY
proname;

View File

@ -0,0 +1,33 @@
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
pr.prokind IN ('f', 'w')
AND typname IN ('trigger', 'event_trigger')
AND lanname NOT IN ('edbspl', 'sql', 'internal')
{% if fnid %}
AND pr.oid = {{fnid}}::oid
{% else %}
AND pronamespace = {{scid}}::oid
{% endif %}
ORDER BY
proname;

View File

@ -0,0 +1,109 @@
{% 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) }}()
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 data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} 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 %}
$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 -%};
{% endif -%}
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
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, '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.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.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if data.description is defined and data.description != o_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 %}

View File

@ -0,0 +1,80 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class FunctionAddTestCase(BaseTestGenerator):
""" This class will add new function under schema node. """
scenarios = [
# Fetching default URL for function node.
('Fetch Function Node URL', dict(
url='/browser/function/obj/'))
]
def runTest(self):
""" This function will add function under schema node. """
super(FunctionAddTestCase, self).runTest()
self = funcs_utils.set_up(self)
db_user = self.server["username"]
data = {
"acl": [
{
"grantee": db_user,
"grantor": db_user,
"privileges":
[
{
"privilege_type": "X",
"privilege": True,
"with_grant": True
}
]
}
],
"arguments": [],
"funcowner": db_user,
"lanname": "sql",
"name": "test_function",
"options": [],
"proleakproof": True,
"pronamespace": 2200,
"prorettypename": "integer",
"prosecdef": True,
"prosrc": "SELECT 1;",
"probin": "$libdir/",
"provolatile": "s",
"seclabels": [],
"variables": []
}
data["name"] = "test_function_add_%s" % str(uuid.uuid4())[1:8]
if self.schema_id:
data['pronamespace'] = self.schema_id
else:
self.schema_id = data['pronamespace']
response = self.tester.post(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id) +
'/' + str(self.schema_id) + '/',
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -0,0 +1,49 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class FunctionDeleteTestCase(BaseTestGenerator):
""" This class will delete the function under schema node. """
scenarios = [
# Fetching default URL for function node.
('Fetch Function Node URL',
dict(url='/browser/function/obj/'))
]
def runTest(self):
""" This function will delete function under database node. """
super(FunctionDeleteTestCase, self).setUp()
self = funcs_utils.set_up(self)
func_name = "test_function_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_function(
self.server, self.db_name, self.schema_name, func_name)
func_id = function_info[0]
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/' + str(func_id),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,49 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class FunctionGetTestCase(BaseTestGenerator):
"""This class will fetch added function under schema node."""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for function node.
('Fetch Function Node URL',
dict(url='/browser/function/obj/'))
]
def runTest(self):
""" This function will delete function under database node. """
super(FunctionGetTestCase, self).setUp()
self = funcs_utils.set_up(self)
func_name = "test_function_get_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_function(
self.server, self.db_name, self.schema_name, func_name)
trigger_func_id = function_info[0]
response = self.tester.get(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/' + str(trigger_func_id),
content_type='html/json')
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,57 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class FunctionPutTestCase(BaseTestGenerator):
""" This class will update new function under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for function node.
('Fetch Function Node URL',
dict(url='/browser/function/obj/'))
]
def runTest(self):
""" This function will update function under database node. """
super(FunctionPutTestCase, self).setUp()
self = funcs_utils.set_up(self)
func_name = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_function(
self.server, self.db_name, self.schema_name, func_name)
func_id = function_info[0]
data = {
"description": "This is a procedure update comment",
"id": func_id
}
put_response = self.tester.put(
self.url + str(utils.SERVER_GROUP) +
'/' + str(self.server_id) + '/' + str(self.db_id) + '/' +
str(self.schema_id) + '/' +
str(func_id),
data=json.dumps(data),
follow_redirects=True)
self.assertEquals(put_response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,90 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class ProcedureAddTestCase(BaseTestGenerator):
""" This class will add new procedure under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for procedure node.
('Fetch Procedure Node URL', dict(
url='/browser/procedure/obj/'))
]
def runTest(self):
""" This function will add procedure under schema node. """
super(ProcedureAddTestCase, self).setUp()
self = funcs_utils.set_up(self)
if self.server_type == "pg" and\
self.server_version < 110000:
message = "Procedures are not supported by PG < 110000."
self.skipTest(message)
db_user = self.server["username"]
data = {
"acl": [
{
"grantee": db_user,
"grantor": db_user,
"privileges":
[
{
"privilege_type": "X",
"privilege": True,
"with_grant": True
}
]
}
],
"arguments": [],
"funcowner": db_user,
"lanname": "sql",
"name": "test_pg_11_proc",
"options": [],
"proleakproof": True,
"pronamespace": 2200,
"prosecdef": True,
"prosrc": "BEGIN RAISE EXCEPTION 'command % is disabled',"
" tg_tag; END;",
"seclabels": [],
"variables": [
{
"name": "enable_sort",
"value": True
}
]
}
data["name"] = "test_proc_add_%s" % str(uuid.uuid4())[1:8]
if self.server_type == 'pg':
data['prosrc'] = 'SELECT 1;'
if self.schema_id:
data['pronamespace'] = self.schema_id
else:
self.schema_id = data['pronamespace']
response = self.tester.post(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id) + '/' +
str(self.schema_id) + '/', data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -0,0 +1,56 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class procedureDeleteTestCase(BaseTestGenerator):
""" This class will delete the procedure under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for procedure node.
('Fetch Procedure Node URL',
dict(url='/browser/procedure/obj/'))
]
def runTest(self):
""" This function will delete procedure under database node. """
super(procedureDeleteTestCase, self).setUp()
self = funcs_utils.set_up(self)
if self.server_type == "pg" and\
self.server_version < 110000:
message = "Procedures are not supported by PG < 110000."
self.skipTest(message)
func_name = "test_procedure_delete_%s" % str(uuid.uuid4())[1:8]
proc_info = funcs_utils.create_procedure(
self.server, self.db_name, self.schema_name, func_name,
self.server_type)
proc_id = proc_info[0]
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/' + str(proc_id),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,55 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class ProcedureGetTestCase(BaseTestGenerator):
"""This class will fetch added procedure under schema node."""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for procedure node.
('Fetch Procedure Node URL',
dict(url='/browser/procedure/obj/'))
]
def runTest(self):
""" This function will get procedure under database node. """
super(ProcedureGetTestCase, self).setUp()
self = funcs_utils.set_up(self)
if self.server_type == "pg" and\
self.server_version < 110000:
message = "Procedures are not supported by PG < 110000."
self.skipTest(message)
func_name = "test_procedure_get_%s" % str(uuid.uuid4())[1:8]
proc_info = funcs_utils.create_procedure(
self.server, self.db_name, self.schema_name, func_name,
self.server_type)
proc_id = proc_info[0]
response = self.tester.get(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/' + str(proc_id),
content_type='html/json')
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,62 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class ProcedurePutTestCase(BaseTestGenerator):
""" This class will update new procedure under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for procedure node.
('Fetch Procedure Node URL',
dict(url='/browser/procedure/obj/'))
]
def runTest(self):
""" This function will update procedure under database node. """
super(ProcedurePutTestCase, self).setUp()
self = funcs_utils.set_up(self)
if self.server_type == "pg" and\
self.server_version < 110000:
message = "Procedures are not supported by PG < 110000."
self.skipTest(message)
func_name = "test_procedure_put_%s" % str(uuid.uuid4())[1:8]
proc_info = funcs_utils.create_procedure(
self.server, self.db_name, self.schema_name, func_name,
self.server_type)
proc_id = proc_info[0]
data = {
"description": "This is procedure update comment",
"id": proc_id
}
put_response = self.tester.put(
self.url + str(utils.SERVER_GROUP) +
'/' + str(self.server_id) + '/' + str(self.db_id) + '/' +
str(self.schema_id) + '/' +
str(proc_id),
data=json.dumps(data),
follow_redirects=True)
self.assertEquals(put_response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -10,14 +10,11 @@
import json
import uuid
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class TriggerFuncAddTestCase(BaseTestGenerator):
@ -32,30 +29,7 @@ class TriggerFuncAddTestCase(BaseTestGenerator):
def runTest(self):
""" This function will add trigger function under schema node. """
super(TriggerFuncAddTestCase, self).runTest()
db_name = parent_node_dict["database"][-1]["db_name"]
schema_info = parent_node_dict["schema"][-1]
server_id = schema_info["server_id"]
db_id = schema_info["db_id"]
prorettypename = "event_trigger/trigger"
server_con = server_utils.connect_server(self, server_id)
if not server_con["info"] == "Server connected.":
raise Exception("Could not connect to server to add resource "
"groups.")
if "type" in server_con["data"]:
if server_con["data"]["version"] < 90300:
prorettypename = "trigger"
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
server_id, db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database to add a function.")
schema_id = schema_info["schema_id"]
schema_name = schema_info["schema_name"]
schema_response = schema_utils.verify_schemas(self.server,
db_name,
schema_name)
if not schema_response:
raise Exception("Could not find the schema to add a function.")
self = funcs_utils.set_up(self)
db_user = self.server["username"]
data = {
"acl": [
@ -79,7 +53,7 @@ class TriggerFuncAddTestCase(BaseTestGenerator):
"options": [],
"proleakproof": True,
"pronamespace": 2200,
"prorettypename": prorettypename,
"prorettypename": self.prorettypename,
"prosecdef": True,
"prosrc": "BEGIN RAISE EXCEPTION 'command % is disabled',"
" tg_tag; END;",
@ -98,16 +72,17 @@ class TriggerFuncAddTestCase(BaseTestGenerator):
for func_type in trigger_func_types:
data['prorettypename'] = func_type
data["name"] = "test_event_add_%s" % str(uuid.uuid4())[1:8]
if schema_id:
data['pronamespace'] = schema_id
if self.schema_id:
data['pronamespace'] = self.schema_id
else:
schema_id = data['pronamespace']
self.schema_id = data['pronamespace']
response = self.tester.post(
self.url + str(utils.SERVER_GROUP) + '/' +
str(server_id) + '/' + str(db_id) + '/' + str(schema_id) +
str(self.server_id) + '/' + str(self.db_id) +
'/' + str(self.schema_id) +
'/', data=json.dumps(data), content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, server_id, db_id)
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -9,15 +9,11 @@
import uuid
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as trigger_funcs_utils
from . import utils as funcs_utils
class TriggerFuncDeleteTestCase(BaseTestGenerator):
@ -29,49 +25,27 @@ class TriggerFuncDeleteTestCase(BaseTestGenerator):
dict(url='/browser/trigger_function/obj/'))
]
def setUp(self):
super(TriggerFuncDeleteTestCase, self).setUp()
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = parent_node_dict["schema"][-1]["schema_name"]
self.schema_id = parent_node_dict["schema"][-1]["schema_id"]
def runTest(self):
""" This function will delete trigger function under database node. """
schema_info = parent_node_dict["schema"][-1]
server_id = schema_info["server_id"]
db_id = schema_info["db_id"]
func_name = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
server_con = server_utils.connect_server(self, server_id)
if not server_con["info"] == "Server connected.":
raise Exception("Could not connect to server to add resource "
"groups.")
server_version = 0
if "type" in server_con["data"]:
if server_con["data"]["version"] < 90300:
server_version = server_con["data"]["version"]
self.function_info = trigger_funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
server_version)
super(TriggerFuncDeleteTestCase, self).setUp()
self = funcs_utils.set_up(self)
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
server_id, db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database to add collation.")
schema_response = schema_utils.verify_schemas(self.server,
self.db_name,
self.schema_name)
if not schema_response:
raise Exception("Could not find the schema to add the collation.")
trigger_func_id = self.function_info[0]
func_name = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
self.server_version)
trigger_func_id = function_info[0]
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' + str(server_id) + '/' +
str(db_id) + '/' +
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/' + str(trigger_func_id),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, server_id, db_id)
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -9,15 +9,11 @@
import uuid
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as trigger_funcs_utils
from . import utils as funcs_utils
class TriggerFuncGetTestCase(BaseTestGenerator):
@ -29,49 +25,26 @@ class TriggerFuncGetTestCase(BaseTestGenerator):
dict(url='/browser/trigger_function/obj/'))
]
def setUp(self):
super(TriggerFuncGetTestCase, self).setUp()
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = parent_node_dict["schema"][-1]["schema_name"]
self.schema_id = parent_node_dict["schema"][-1]["schema_id"]
def runTest(self):
""" This function will delete trigger function under database node. """
schema_info = parent_node_dict["schema"][-1]
server_id = schema_info["server_id"]
db_id = schema_info["db_id"]
func_name = "test_event_get_%s" % str(uuid.uuid4())[1:8]
db_user = self.server["username"]
server_con = server_utils.connect_server(self, server_id)
if not server_con["info"] == "Server connected.":
raise Exception("Could not connect to server to add resource "
"groups.")
server_version = 0
if "type" in server_con["data"]:
if server_con["data"]["version"] < 90300:
server_version = server_con["data"]["version"]
self.function_info = trigger_funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
server_version)
super(TriggerFuncGetTestCase, self).setUp()
self = funcs_utils.set_up(self)
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
server_id, db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database to add collation.")
schema_response = schema_utils.verify_schemas(self.server,
self.db_name,
self.schema_name)
if not schema_response:
raise Exception("Could not find the schema to add the collation.")
trigger_func_id = self.function_info[0]
func_name = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
self.server_version)
trigger_func_id = function_info[0]
response = self.tester.get(
self.url + str(utils.SERVER_GROUP) + '/' + str(server_id) + '/' +
str(db_id) + '/' +
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/' + str(trigger_func_id),
content_type='html/json')
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, server_id, db_id)
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -10,15 +10,11 @@
import json
import uuid
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as trigger_funcs_utils
from . import utils as funcs_utils
class TriggerFuncPutTestCase(BaseTestGenerator):
@ -30,63 +26,33 @@ class TriggerFuncPutTestCase(BaseTestGenerator):
dict(url='/browser/trigger_function/obj/'))
]
def setUp(self):
super(TriggerFuncPutTestCase, self).setUp()
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = parent_node_dict["schema"][-1]["schema_name"]
self.schema_id = parent_node_dict["schema"][-1]["schema_id"]
def runTest(self):
""" This function will update trigger function under database node. """
schema_info = parent_node_dict["schema"][-1]
server_id = schema_info["server_id"]
db_id = schema_info["db_id"]
func_name = "test_event_put_%s" % str(uuid.uuid4())[1:8]
server_con = server_utils.connect_server(self, server_id)
if not server_con["info"] == "Server connected.":
raise Exception("Could not connect to server to add resource "
"groups.")
server_version = 0
if "type" in server_con["data"]:
if server_con["data"]["version"] < 90300:
server_version = server_con["data"]["version"]
self.function_info = trigger_funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
server_version)
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
server_id, db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database to add collation.")
schema_response = schema_utils.verify_schemas(self.server,
self.db_name,
self.schema_name)
if not schema_response:
raise Exception("Could not find the schema to add the collation.")
func_name = self.function_info[1]
func_response = trigger_funcs_utils.verify_trigger_function(
self.server,
self.db_name,
func_name)
if not func_response:
raise Exception("Could not find the trigger function to update"
" it's details.")
super(TriggerFuncPutTestCase, self).setUp()
self = funcs_utils.set_up(self)
func_name = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
self.server_version)
trigger_func_id = function_info[0]
trigger_func_id = self.function_info[0]
data = {
"description": "This is trigger function update comment",
"description": "This is a trigger function update comment",
"id": trigger_func_id
}
put_response = self.tester.put(
self.url + str(utils.SERVER_GROUP) +
'/' + str(server_id) + '/' + str(db_id) + '/' +
'/' + str(self.server_id) + '/' + str(self.db_id) + '/' +
str(self.schema_id) + '/' +
str(trigger_func_id),
data=json.dumps(data),
follow_redirects=True)
self.assertEquals(put_response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, server_id, db_id)
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -13,6 +13,11 @@ import sys
import traceback
from regression.python_test_utils import test_utils as utils
from pgadmin.utils import server_utils as server_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
def create_trigger_function(server, db_name, schema_name, func_name,
@ -92,3 +97,118 @@ def verify_trigger_function(server, db_name, func_name):
functions = pg_cursor.fetchone()
connection.close()
return functions
def create_procedure(server, db_name, schema_name, func_name, s_type):
"""This function add the procedure to schema"""
try:
connection = utils.get_db_connection(db_name,
server['username'],
server['db_password'],
server['host'],
server['port'],
server['sslmode'])
pg_cursor = connection.cursor()
if s_type == 'pg':
query = "CREATE PROCEDURE " + schema_name + "." + func_name + \
"()" \
" LANGUAGE 'sql'" \
" SECURITY DEFINER AS $$" \
" SELECT 1; $$;"
else:
query = "CREATE PROCEDURE " + schema_name + "." + func_name + \
"()" \
" SECURITY DEFINER AS $BODY$ BEGIN" \
" NULL; END; $BODY$"
pg_cursor.execute(query)
connection.commit()
# Get 'oid' from newly created function
pg_cursor.execute("SELECT pro.oid, pro.proname FROM"
" pg_proc pro WHERE pro.proname='%s'" %
func_name)
functions = pg_cursor.fetchone()
connection.close()
return functions
except Exception:
traceback.print_exc(file=sys.stderr)
def create_function(server, db_name, schema_name, func_name):
"""This function add the procedure to schema"""
try:
connection = utils.get_db_connection(db_name,
server['username'],
server['db_password'],
server['host'],
server['port'],
server['sslmode'])
pg_cursor = connection.cursor()
query = "CREATE FUNCTION " + schema_name + "." + func_name + \
"()" \
" RETURNS integer LANGUAGE 'sql' STABLE" \
" SECURITY DEFINER AS $$" \
" SELECT 1; $$;"
pg_cursor.execute(query)
connection.commit()
# Get 'oid' from newly created function
pg_cursor.execute("SELECT pro.oid, pro.proname FROM"
" pg_proc pro WHERE pro.proname='%s'" %
func_name)
functions = pg_cursor.fetchone()
connection.close()
return functions
except Exception:
traceback.print_exc(file=sys.stderr)
def verify_procedure(server, db_name, proc_name):
"""This function verifies the procedure in db"""
connection = utils.get_db_connection(db_name,
server['username'],
server['db_password'],
server['host'],
server['port'],
server['sslmode'])
pg_cursor = connection.cursor()
pg_cursor.execute("SELECT pro.oid, pro.proname FROM"
" pg_proc pro WHERE pro.proname='%s'" %
proc_name)
procs = pg_cursor.fetchone()
connection.close()
return procs
def set_up(obj):
"""Common set up function"""
from regression import parent_node_dict
obj.db_name = parent_node_dict["database"][-1]["db_name"]
schema_info = parent_node_dict["schema"][-1]
obj.server_id = schema_info["server_id"]
obj.db_id = schema_info["db_id"]
obj.prorettypename = "event_trigger/trigger"
server_con = server_utils.connect_server(obj, obj.server_id)
if not server_con["info"] == "Server connected.":
raise Exception("Could not connect to server.")
if "version" in server_con["data"]:
obj.server_version = server_con["data"]["version"]
if server_con["data"]["version"] < 90300:
obj.prorettypename = "trigger"
if "type" in server_con["data"]:
obj.server_type = server_con["data"]["type"]
db_con = database_utils.connect_database(obj, utils.SERVER_GROUP,
obj.server_id,
obj.db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database.")
obj.schema_id = schema_info["schema_id"]
obj.schema_name = schema_info["schema_name"]
schema_response = schema_utils.verify_schemas(obj.server,
obj.db_name,
obj.schema_name)
if not schema_response:
raise Exception("Could not find the schema.")
return obj

View File

@ -51,7 +51,9 @@ class PGChildModule(object):
def __init__(self, *args, **kwargs):
self.min_ver = 0
self.max_ver = 1000000000
self.max_ver = 1100000000
self.min_ppasver = 0
self.max_ppasver = 1100000000
self.server_type = None
self.min_gpdbver = 80323
self.max_gpdbver = 1000000000
@ -72,6 +74,9 @@ class PGChildModule(object):
if self.server_type is None or manager.server_type in self.server_type:
min_server_version = self.min_ver
max_server_version = self.max_ver
if manager.server_type == 'ppas':
min_server_version = self.min_ppasver
max_server_version = self.max_ppasver
if manager.server_type == 'gpdb':
min_server_version = self.min_gpdbver
max_server_version = self.max_gpdbver

View File

@ -365,8 +365,11 @@ def init_function(node_type, sid, did, scid, fid, trid=None):
# Check server type is ppas or not
ppas_server = False
is_proc_supported = False
if server_type == 'ppas':
ppas_server = True
else:
is_proc_supported = True if manager.version >= 110000 else False
# Set the template path required to read the sql files
template_path = 'debugger/sql'
@ -395,7 +398,10 @@ def init_function(node_type, sid, did, scid, fid, trid=None):
sql = render_template(
"/".join([template_path, 'get_function_debug_info.sql']),
is_ppas_database=ppas_server,
hasFeatureFunctionDefaults=True, fid=fid
hasFeatureFunctionDefaults=True,
fid=fid,
is_proc_supported=is_proc_supported
)
status, r_set = conn.execute_dict(sql)
if not status:
@ -509,6 +515,7 @@ def init_function(node_type, sid, did, scid, fid, trid=None):
'oid': fid,
'name': r_set['rows'][0]['name'],
'is_func': r_set['rows'][0]['isfunc'],
'is_ppas_database': ppas_server,
'is_callable': False,
'schema': r_set['rows'][0]['schemaname'],
'language': r_set['rows'][0]['lanname'],
@ -765,6 +772,7 @@ def initialize_target(debug_type, sid, did, scid, func_id, tri_id=None):
'oid': func_data['oid'],
'name': func_data['name'],
'is_func': func_data['is_func'],
'is_ppas_database': func_data['is_ppas_database'],
'is_callable': func_data['is_callable'],
'schema': func_data['schema'],
'language': func_data['language'],
@ -1062,7 +1070,8 @@ def start_debugger_listener(trans_id):
func_name=func_name,
is_func=session_function_data['is_func'],
ret_type=session_function_data['return_type'],
data=session_function_data['args_value']
data=session_function_data['args_value'],
is_ppas_database=session_function_data['is_ppas_database']
)
status, result = conn.execute_async(str_query)
@ -1946,8 +1955,9 @@ def poll_end_execution_result(trans_id):
status, result = conn.poll()
session_function_data = session['functionData'][str(trans_id)]
if status == ASYNC_OK and \
not session_function_data['is_func'] and \
session_function_data['language'] == 'edbspl':
not session_function_data['is_func'] and\
(session_function_data['language'] == 'edbspl' or
session_function_data['language'] == 'plpgsql'):
status = 'Success'
additional_msgs = conn.messages()
if len(additional_msgs) > 0:

View File

@ -1,6 +1,8 @@
{### Create executer function for plpgsql function debugging ###}
{% if not is_func %}
{% if is_ppas_database and not is_func %}
EXEC {{ func_name }} (
{% elif not is_func %}
CALL {{ func_name }} (
{% elif ret_type == 'record' %}
SELECT {{ func_name }} (
{% else %}

View File

@ -41,7 +41,11 @@ SELECT
0 AS pkgconsoid,
n.oid AS schema,
n.nspname AS schemaname,
true AS isfunc,
{% if is_proc_supported %}
CASE WHEN p.prokind in ('f', 'w') THEN TRUE ELSE FALSE END AS isfunc,
{% else %}
TRUE AS isfunc,
{% endif %}
{%endif%}
pg_catalog.pg_get_function_identity_arguments(p.oid) AS signature,
@ -61,4 +65,4 @@ FROM
{% endif %}
{% if fid %}
WHERE p.oid = {{fid}}::oid;
{% endif %}
{% endif %}

View File

@ -75,7 +75,8 @@ def get_version_mapping(template):
{'name': "default", 'number': 0}
)
return ({'name': "10_plus", 'number': 100000},
return ({'name': "11_plus", 'number': 110000},
{'name': "10_plus", 'number': 100000},
{'name': "9.6_plus", 'number': 90600},
{'name': "9.5_plus", 'number': 90500},
{'name': "9.4_plus", 'number': 90400},