Add support for Event Triggers.

This commit is contained in:
Harshal Dhumal 2016-03-10 13:38:31 +00:00 committed by Dave Page
parent 3b03c17f2b
commit 986375d60e
14 changed files with 980 additions and 0 deletions

View File

@ -0,0 +1,664 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
import re
from flask import render_template, make_response, request, jsonify
from flask.ext.babel import gettext
from pgadmin.utils.ajax import make_json_response, \
make_response as ajax_response, internal_server_error
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.browser.collection import CollectionNodeModule
import pgadmin.browser.server_groups.servers.databases as database
from pgadmin.utils.ajax import precondition_required
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from functools import wraps
class EventTriggerModule(CollectionNodeModule):
"""
class EventTriggerModule(CollectionNodeModule)
A module class for Event trigger node derived from CollectionNodeModule.
Methods:
-------
* __init__(*args, **kwargs)
- Method is used to initialize the EventTriggerModule and it's base module.
* get_nodes(gid, sid, did)
- Method is used to generate the browser collection node.
* script_load()
- Load the module script for Event trigger, when any of the database node is
initialized.
"""
NODE_TYPE = 'event_trigger'
COLLECTION_LABEL = gettext("Event Triggers")
def __init__(self, *args, **kwargs):
"""
Method is used to initialize the EventTriggerModule and it's base module.
Args:
*args:
**kwargs:
"""
super(EventTriggerModule, self).__init__(*args, **kwargs)
self.min_ver = 90300
self.max_ver = None
def get_nodes(self, gid, sid, did):
"""
Generate the event_trigger node
"""
yield self.generate_browser_collection_node(sid)
@property
def node_inode(self):
"""
If a node have child return True otherwise False
"""
return False
@property
def script_load(self):
"""
Load the module script for event_trigger, when any of the database node is
initialized.
"""
return database.DatabaseModule.NODE_TYPE
blueprint = EventTriggerModule(__name__)
class EventTriggerView(PGChildNodeView):
"""
class EventTriggerView(PGChildNodeView)
A view class for event trigger node derived from PGChildNodeView.
This class is responsible for all the stuff related to view like
updating event trigger node, showing properties, showing sql in sql
pane.
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the EventTriggerView and it's base view.
* module_js()
- This property defines (if javascript) exists for this node.
Override this property for your own logic
* check_precondition()
- This function will behave as a decorator which will checks
database connection before running view, it will also attaches
manager,conn & template_path properties to self
* list()
- This function is used to list all the event trigger nodes within
that collection.
* nodes()
- This function will used to create all the child node within that collection.
Here it will create all the event trigger node.
* properties(gid, sid, did, etid)
- This function will show the properties of the selected
event trigger node
* update(gid, sid, did, etid)
- This function will update the data for the selected event trigger node.
* msql(gid, sid, did, etid)
- This function is used to return modified SQL for the selected
event trigger node.
* get_sql(data, etid)
- This function will generate sql from model data
* sql(gid, sid, did, etid):
- This function will generate sql to show it in sql pane for the selected
event trigger node.
* get_event_funcs(gid, sid, did, etid):
- This function gets the event functions and returns an ajax response
for the event trigger node.
* dependents(gid, sid, did, etid):
- This function get the dependents and return ajax response for the
event trigger node.
* dependencies(self, gid, sid, did, etid):
- This function get the dependencies and return ajax response for the
event trigger node.
"""
node_type = blueprint.node_type
parent_ids = [
{'type': 'int', 'id': 'gid'},
{'type': 'int', 'id': 'sid'},
{'type': 'int', 'id': 'did'}
]
ids = [
{'type': 'int', 'id': 'etid'}
]
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'}
],
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'children': [{'get': 'children'}],
'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}],
'stats': [{'get': 'statistics'}],
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'fopts': [{'get': 'get_event_funcs'}, {'get': 'get_event_funcs'}]
})
def module_js(self):
"""
This property defines whether javascript exists for this node.
"""
return make_response(
render_template(
"event_triggers/js/event_trigger.js",
_=gettext
),
200, {'Content-Type': 'application/x-javascript'}
)
def check_precondition(f):
"""
This function will behave as a decorator which will checks
database connection before running view, it will also attaches
manager,conn & template_path properties to self
"""
@wraps(f)
def wrap(*args, **kwargs):
# Here args[0] will hold self & kwargs will hold gid,sid,did
self = args[0]
self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
self.conn = self.manager.connection(did=kwargs['did'])
# If DB not connected then return error to browser
if not self.conn.connected():
return precondition_required(
gettext(
"Connection to the server has been lost!"
)
)
ver = self.manager.version
if ver >= 90300:
self.template_path = 'event_triggers/sql/9.3_plus'
return f(*args, **kwargs)
return wrap
@check_precondition
def list(self, gid, sid, did):
"""
This function is used to list all the event trigger
nodes within that collection.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
sql = render_template("/".join([self.template_path, 'properties.sql']))
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
return ajax_response(
response=res['rows'],
status=200
)
@check_precondition
def nodes(self, gid, sid, did):
"""
This function is used to create all the child nodes within the collection.
Here it will create all the event trigger nodes.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
result = []
sql = render_template("/".join([self.template_path, 'nodes.sql']))
status, res = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=res)
for row in res['rows']:
result.append(
self.blueprint.generate_browser_node(
row['oid'],
did,
row['name'],
icon="icon-%s" % self.node_type
))
return make_json_response(
data=result,
status=200
)
@check_precondition
def properties(self, gid, sid, did, etid):
"""
This function is used to list all the event trigger
nodes within that collection.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
sql = render_template("/".join([self.template_path, 'properties.sql']), etid=etid, conn=self.conn)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
result = res['rows'][0]
sec_labels = []
if 'seclabels' in result and result['seclabels'] is not None:
for sec in result['seclabels']:
sec = re.search(r'([^=]+)=(.*$)', sec)
sec_labels.append({
'provider': sec.group(1),
'securitylabel': sec.group(2)
})
result.update({"seclabels": sec_labels})
return ajax_response(
response=result,
status=200
)
@check_precondition
def create(self, gid, sid, did):
"""
This function will create a event trigger object.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
data = request.form if request.form else json.loads(request.data.decode())
required_args = {
'name':'Name',
'eventowner':'Owner',
'eventfunname':'Trigger function',
'enabled':'Enabled status',
'eventname':'Events'
}
err = []
for arg in required_args:
if arg not in data:
err.append(required_args.get(arg, arg))
if err:
return make_json_response(
status=400,
success=0,
errormsg=gettext(
"Couldn't find the required parameter/s %s." % err
)
)
try:
sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
sql = render_template("/".join([self.template_path, 'grant.sql']), data=data, conn=self.conn)
sql = sql.strip('\n').strip(' ')
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
sql = render_template("/".join([self.template_path, 'get_oid.sql']), data=data)
status, etid = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=etid)
return jsonify(
node=self.blueprint.generate_browser_node(
etid,
did,
data['name'],
icon="icon-%s" % self.node_type
)
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def update(self, gid, sid, did, etid):
"""
This function will update the data for the selected
event trigger node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
data = request.form if request.form else json.loads(request.data.decode())
try:
sql = self.get_sql(data, etid)
sql = sql.strip('\n').strip(' ')
if sql != "":
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
sql = render_template("/".join([self.template_path, 'get_oid.sql']), data=data)
status, etid = self.conn.execute_scalar(sql)
return jsonify(
node=self.blueprint.generate_browser_node(
etid,
did,
data['name'],
icon="icon-%s" % self.node_type
)
)
else:
return make_json_response(
success=1,
info="Nothing to update",
data={
'id': etid,
'sid': sid,
'gid': gid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def delete(self, gid, sid, did, etid):
"""
This function will delete an existing event trigger object.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
if self.cmd == 'delete':
# This is a cascade operation
cascade = True
else:
cascade = False
try:
sql = render_template("/".join([self.template_path, 'delete.sql']), etid=etid)
status, name = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=name)
sql = render_template("/".join([self.template_path, 'delete.sql']), name=name, cascade=cascade)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info=gettext("Event trigger dropped"),
data={
'id': etid,
'sid': sid,
'gid': gid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def msql(self, gid, sid, did, etid = None):
"""
This function is used to return modified SQL for the selected
event trigger node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
data = {}
for k, v in request.args.items():
try:
data[k] = json.loads(v)
except ValueError:
data[k] = v
try:
sql = self.get_sql(data, etid)
sql = sql.strip('\n').strip(' ')
return make_json_response(
data=sql,
status=200
)
except Exception as e:
return internal_server_error(errormsg=str(e))
def get_sql(self, data, etid=None):
"""
This function will generate sql from model data.
Args:
data: Contains the data of the selected event trigger node.
etid: Event trigger ID
Returns:
"""
required_args = [
'name'
]
if etid is not None:
sql = render_template("/".join([self.template_path, 'properties.sql']), etid=etid)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
old_data = res['rows'][0]
for arg in required_args:
if arg not in data:
data[arg] = old_data[arg]
sql = render_template("/".join([self.template_path, 'update.sql']), data=data, o_data=old_data)
else:
required_args = {
'name':'Name',
'eventowner':'Owner',
'eventfunname':'Trigger function',
'enabled':'Enabled status',
'eventname':'Events'
}
err = []
for arg in required_args:
if arg not in data:
err.append(required_args.get(arg, arg))
if err:
return make_json_response(
status=400,
success=0,
errormsg=gettext(
"Couldn't find the required parameter/s %s." % err
)
)
sql = render_template("/".join([self.template_path, 'create.sql']), data=data)
sql += "\n"
sql += render_template("/".join([self.template_path, 'grant.sql']), data=data)
return sql
@check_precondition
def sql(self, gid, sid, did, etid):
"""
This function will generate sql to show in the sql pane for the selected
event trigger node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
try:
sql = render_template("/".join([self.template_path, 'properties.sql']), etid=etid)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
result = res['rows'][0]
sql = render_template("/".join([self.template_path, 'create.sql']), data=result, conn=self.conn)
sql += "\n\n"
sql += render_template("/".join([self.template_path, 'grant.sql']), data=result, conn=self.conn)
db_sql = render_template("/".join([self.template_path, 'get_db.sql']), did=did)
status, db_name = self.conn.execute_scalar(db_sql)
if not status:
return internal_server_error(errormsg=db_name)
sql_header = "-- Event Trigger: {0} on database {1}\n\n-- ".format(result['name'], db_name)
sql_header += render_template(
"/".join([self.template_path, 'delete.sql']),
name=result['name'], )
sql_header += "\n"
sql = sql_header + sql
return ajax_response(response=sql)
except Exception as e:
return ajax_response(response=str(e))
@check_precondition
def get_event_funcs(self, gid, sid, did, etid=None):
"""
This function gets the event functions and returns an ajax response
for the event trigger node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
Returns:
"""
res = [{ 'label': '', 'value': '' }]
sql = render_template("/".join([self.template_path, 'eventfunctions.sql']))
status, rest = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rest)
for row in rest['rows']:
res.append(
{'label': row['tfname'], 'value': row['tfname']}
)
return make_json_response(
data=res,
status=200
)
@check_precondition
def dependents(self, gid, sid, did, etid=None):
"""
This function gets the dependents and returns an ajax response
for the event trigger node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
"""
dependents_result = self.get_dependents(self.conn, etid)
return ajax_response(
response=dependents_result,
status=200
)
@check_precondition
def dependencies(self, gid, sid, did, etid):
"""
This function gets the dependencies and returns an ajax response
for the event trigger node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
etid: Event trigger ID
"""
dependencies_result = self.get_dependencies(self.conn, etid)
return ajax_response(
response=dependencies_result,
status=200
)
EventTriggerView.register_node_view(blueprint)

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

View File

@ -0,0 +1,180 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, alertify) {
// Extend the browser's node model class to create a security model
var SecurityLabelModel = pgAdmin.Browser.Node.Model.extend({
defaults: {
provider: undefined,
securitylabel: undefined
},
// Define the schema for the Security Label
schema: [
{id: 'provider', label:'Provider', type:'text', group: null, editable: true},
{id: 'securitylabel', label:'Security Label', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
],
validate: function() {
// Clear any existing errors.
this.errorModel.clear()
if (_.isUndefined(this.get('provider')) || String(this.get('provider')).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Provider can not be empty!') }}';
this.errorModel.set('provider',msg);
return msg;
}
if (_.isUndefined(this.get('securitylabel')) || String(this.get('securitylabel')).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Security Label can not be empty!') }}';
this.errorModel.set('securitylabel',msg);
return msg;
}
return null;
}
});
// Extend the browser's collection class for event trigger collection
if (!pgBrowser.Nodes['coll-event_trigger']) {
var databases = pgAdmin.Browser.Nodes['coll-event_trigger'] =
pgAdmin.Browser.Collection.extend({
node: 'event_trigger',
label: '{{ _('Event Trigger') }}',
type: 'coll-event_trigger',
columns: ['name', 'eventowner', 'comment']
});
};
// Extend the browser's node class for event triggers node
if (!pgBrowser.Nodes['event_trigger']) {
pgAdmin.Browser.Nodes['event_trigger'] = pgAdmin.Browser.Node.extend({
parent_type: 'database',
type: 'event_trigger',
label: '{{ _('Event Trigger') }}',
hasSQL: true,
hasDepends: true,
canDrop: true,
Init: function() {
/* Avoid mulitple registration of menus */
if (this.initialized)
return;
this.initialized = true;
pgBrowser.add_menus([{
name: 'create_event_trigger_on_coll', node: 'coll-event_trigger', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Event Trigger...') }}',
icon: 'wcTabIcon pg-icon-event_trigger', data: {action: 'create'}
},{
name: 'create_event_trigger', node: 'event_trigger', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Event Trigger...') }}',
icon: 'wcTabIcon pg-icon-event_trigger', data: {action: 'create'}
}
]);
},
// Define the model for event trigger node
model: pgAdmin.Browser.Node.Model.extend({
defaults: {
oid: undefined,
name: undefined,
eventowner: undefined,
comment: undefined,
enabled: undefined,
eventfuncoid: undefined,
eventfunname: undefined,
eventname: undefined,
when: undefined,
xmin: undefined,
source: undefined,
language: undefined
},
// Define the schema for the event trigger node
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
type: 'text'
},{
id: 'oid', label:'{{ _('OID') }}', cell: 'string',
type: 'text', mode: ['properties']
},{
id: 'eventowner', label:'{{ _('Owner') }}', cell: 'string',
type: 'text', mode: ['properties', 'edit','create'], node: 'role',
control: Backform.NodeListByNameControl
},{
id: 'comment', label:'{{ _('Comment') }}', type: 'multiline'
},{
id: 'enabled', label:'{{ _('Enabled status') }}',
type:"radio", group: "Definition", mode: ['properties', 'edit','create'],
options: [
{label: "Enable", value: "O"},
{label: "Disable", value: "D"},
{label: "Replica", value: "R"},
{label: "Always", value: "A"}
]
},{
id: 'eventfunname', label:'{{ _('Trigger function') }}',
type: 'text', control: 'node-ajax-options', group: "Definition",
url:'fopts'
},{
id: 'eventname', label:'{{ _('Events') }}',
type:"radio", group: "Definition", cell: 'string',
options: [
{label: "DDL COMMAND START", value: "DDL_COMMAND_START"},
{label: "DDL COMMAND END", value: "DDL_COMMAND_END"},
{label: "SQL DROP", value: "SQL_DROP"}
]
},{
id: 'when', label:'{{ _('When') }}', type: 'multiline', group: "Definition",
},{
id: 'providers', label: 'Security Labels', type: 'collection', group: "Security Labels",
model: SecurityLabelModel, control: 'unique-col-collection', mode: ['edit', 'create'],
canAdd: true, canDelete: true, uniqueCol : ['provider'],
columns: ['provider','securitylabel']
}
],
// event trigger model data validation.
validate: function() {
var msg = undefined;
// Clear any existing error msg.
this.errorModel.clear();
if (_.isUndefined(this.get('name'))
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Event trigger name can not be empty!') }}';
this.errorModel.set('name', msg);
return msg;
}
if (_.isUndefined(this.get('eventowner'))
|| String(this.get('eventowner')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Event trigger owner can not be empty!') }}';
this.errorModel.set('eventowner', msg);
return msg;
}
if (_.isUndefined(this.get('enabled'))) {
msg = '{{ _('Event trigger enabled status can not be empty!') }}';
this.errorModel.set('enabled', msg);
return msg;
}
if (_.isUndefined(this.get('eventfunname'))
|| String(this.get('eventfunname')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Event trigger function can not be empty!') }}';
this.errorModel.set('eventfunname', msg);
return msg;
}
if (_.isUndefined(this.get('eventname'))) {
msg = '{{ _('Event trigger event can not be empty!') }}';
this.errorModel.set('eventname', msg);
return msg;
}
return null;
}
})
});
}
return pgBrowser.Nodes['coll-event_trigger'];
});

View File

@ -0,0 +1,7 @@
{% if data %}
CREATE EVENT TRIGGER {{ conn|qtIdent(data.name) }} ON {{data.eventname}}
{% if data.when %}
WHEN TAG IN ({{data.when}})
{% endif %}
EXECUTE PROCEDURE {{data.eventfunname}}();
{% endif %}

View File

@ -0,0 +1,7 @@
{% if etid %}
SELECT e.evtname AS name FROM pg_event_trigger e
WHERE e.oid={{etid}}::int;
{% endif %}
{% if name %}
DROP EVENT TRIGGER IF EXISTS {{ conn|qtIdent(name) }}{% if cascade%} CASCADE{% endif %};
{% endif %}

View File

@ -0,0 +1,4 @@
SELECT quote_ident(nspname) || '.' || quote_ident(proname) AS tfname
FROM pg_proc p, pg_namespace n, pg_language l
WHERE p.pronamespace = n.oid AND p.prolang = l.oid AND p.pronargs = 0 AND l.lanname != 'sql' AND prorettype::regtype::text = 'event_trigger'
ORDER BY nspname ASC, proname ASC

View File

@ -0,0 +1 @@
SELECT db.datname as name FROM pg_database as db WHERE db.oid = {{did}}

View File

@ -0,0 +1,5 @@
{# The Sql below will provide oid for newly created event_trigger #}
{% if data %}
SELECT e.oid from pg_event_trigger e
WHERE e.evtname = {{ data.name|qtLiteral }}
{% endif %}

View File

@ -0,0 +1,26 @@
{% import 'macros/security.macros' as SECLABLE %}
{% if data %}
{% if data.enabled and data.enabled != "O" %}
ALTER EVENT TRIGGER {{ conn|qtIdent(data.name) }}
{% if data.enabled == "D" %}
DISABLE;
{% elif data.enabled == "R" %}
ENABLE REPLICA;
{% elif data.enabled == "A" %}
ENABLE ALWAYS;
{% endif %}
{% endif %}
{% if data.comment %}
COMMENT ON EVENT TRIGGER {{ conn|qtIdent(data.name) }}
IS {{ data.comment|qtLiteral }};
{% endif %}
{% if data.providers and data.providers|length > 0 %}
{% for r in data.providers %}
{{ SECLABLE.APPLY(conn, 'EVENT TRIGGER', data.name, r.provider, r.securitylabel) }}
{% endfor %}{% endif %}
ALTER EVENT TRIGGER {{ conn|qtIdent(data.name) }}
OWNER TO {{data.eventowner}};
{% endif %}

View File

@ -0,0 +1,3 @@
SELECT e.oid, e.evtname AS name
FROM pg_event_trigger e
ORDER BY e.evtname

View File

@ -0,0 +1,17 @@
SELECT e.oid, e.xmin, e.evtname AS name, upper(e.evtevent) AS eventname,
pg_catalog.pg_get_userbyid(e.evtowner) AS eventowner,
e.evtenabled AS enabled,
e.evtfoid AS eventfuncoid, quote_ident(n.nspname) || '.' || e.evtfoid::regproc AS eventfunname,
array_to_string(array(select quote_literal(x) from unnest(evttags) as t(x)), ', ') AS when,
pg_catalog.obj_description(e.oid, 'pg_event_trigger') AS comment,
(SELECT array_agg(provider || '=' || label) FROM pg_shseclabel sl1 WHERE sl1.objoid=e.oid) AS seclabels,
p.prosrc AS source, p.pronamespace AS schemaoid, l.lanname AS language
FROM pg_event_trigger e
LEFT OUTER JOIN pg_proc p ON p.oid=e.evtfoid
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang,
pg_namespace n
WHERE p.pronamespace = n.oid
{% if etid %}
AND e.oid={{etid}}::int
{% endif %}
ORDER BY e.evtname

View File

@ -0,0 +1,66 @@
{% import 'macros/security.macros' as SECLABLE %}
{% if data %}
{% if (data.eventfunname and data.eventfunname != o_data.eventfunname) or
(data.eventname and data.eventname != o_data.eventname) or
(data.when and data.when != o_data.when) %}
DROP EVENT TRIGGER IF EXISTS {{ conn|qtIdent(o_data.name) }};
CREATE EVENT TRIGGER {{ conn|qtIdent(data.name) if data.name else conn|qtIdent(o_data.name) }} ON {{ data.eventname if data.eventname else o_data.eventname }}
{% if data.when or o_data.when %}
WHEN TAG IN ({{ data.when if data.when else o_data.when }})
{% endif %}
EXECUTE PROCEDURE {{ data.eventfunname if data.eventfunname else o_data.eventfunname }}();
{% else %}
{% if data.name and data.name != o_data.name %}
ALTER EVENT TRIGGER {{ conn|qtIdent(o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{% endif %}
{% if data.comment and data.comment != o_data.comment %}
COMMENT ON EVENT TRIGGER {{ conn|qtIdent(data.name) }}
IS '{{ data.comment }}';
{% endif %}
{% if data.enabled and data.enabled != o_data.enabled %}
ALTER EVENT TRIGGER {{ conn|qtIdent(data.name) }}
{% if data.enabled == "O" %}
ENABLE;
{% elif data.enabled == "D" %}
DISABLE;
{% elif data.enabled == "R" %}
ENABLE REPLICA;
{% elif data.enabled == "A" %}
ENABLE ALWAYS;
{% endif %}
{% endif %}
{% endif %}
{% if data.providers and
data.providers|length > 0
%}{% set seclabels = data.providers %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'EVENT TRIGGER', data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'EVENT TRIGGER', data.name, r.provider, r.securitylabel) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'EVENT TRIGGER', data.name, r.provider, r.securitylabel) }}
{% endfor %}
{% endif %}
{% endif %}
{% if data.eventowner and data.eventowner != o_data.eventowner %}
ALTER EVENT TRIGGER {{ conn|qtIdent(data.name) }}
OWNER TO {{data.eventowner}};
{% endif %}