1) Add support of Compound Triggers for EPAS 12+. Fixes #4144.
2) Ensure enable trigger menu should be visible when trigger is disabled. Fixes #4578.
75
docs/en_US/compound_trigger_dialog.rst
Normal file
@@ -0,0 +1,75 @@
|
||||
.. _compound_trigger_dialog:
|
||||
|
||||
********************************
|
||||
`Compound Trigger Dialog`:index:
|
||||
********************************
|
||||
|
||||
Use the *Compound Trigger* dialog to create a compound trigger or modify an
|
||||
existing compound trigger. *Compound Trigger* is supported only for EPAS server
|
||||
12 and above. A compound trigger executes a specified code when certain events
|
||||
occur.
|
||||
|
||||
The *Compound Trigger* dialog organizes the development of a compound trigger
|
||||
through the following dialog tabs: *General*, *Events*, and *Code*. The *SQL*
|
||||
tab displays the SQL code generated by dialog selections.
|
||||
|
||||
.. image:: images/compound_trigger_general.png
|
||||
:alt: Compound Trigger dialog general tab
|
||||
:align: center
|
||||
|
||||
Use the fields in the *General* tab to identify the compound trigger:
|
||||
|
||||
* Use the *Name* field to add a descriptive name for the compound trigger. This
|
||||
must be distinct from the name of any other compound trigger for the same table.
|
||||
The name will be displayed in the *pgAdmin* tree control.
|
||||
* Store notes about the compound trigger in the *Comment* field.
|
||||
|
||||
Click the *Events* tab to continue.
|
||||
|
||||
.. image:: images/compound_trigger_events.png
|
||||
:alt: Compound Trigger dialog events tab
|
||||
:align: center
|
||||
|
||||
Use the fields in the *Events* tab to specify how and when the compound trigger fires:
|
||||
|
||||
* Select the type of event(s) that will invoke the compound trigger; to select
|
||||
an event type, move the switch next to the event to the *YES* position.
|
||||
The supported event types are *INSERT*, *UPDATE*, *DELETE*.
|
||||
* Use the *When* field to provide a boolean condition that will invoke the
|
||||
compound trigger.
|
||||
* If defining a column-specific compound trigger, use the *Columns* field to
|
||||
specify the columns or columns that are the target of the compound trigger.
|
||||
|
||||
Click the *Code* tab to continue.
|
||||
|
||||
.. image:: images/compound_trigger_code.png
|
||||
:alt: Compound Trigger dialog code tab
|
||||
:align: center
|
||||
|
||||
Use the *Code* field to specify the code for the four timing events
|
||||
*BEFORE STATEMENT*, *AFTER STATEMENT*, *BEFORE EACH ROW*, *AFTER EACH ROW*
|
||||
that will be invoked when the compound trigger fires. Basic template is provided
|
||||
with place holders.
|
||||
|
||||
Click the *SQL* tab to continue.
|
||||
|
||||
Your entries in the *Compound Trigger* dialog generate a SQL command (see an example
|
||||
below). Use the *SQL* tab for review; revisit or switch tabs to make any changes
|
||||
to the SQL command.
|
||||
|
||||
Example
|
||||
*******
|
||||
|
||||
The following is an example of the sql command generated by user selections in
|
||||
the *Compound Trigger* dialog:
|
||||
|
||||
.. image:: images/compound_trigger_sql.png
|
||||
:alt: Compound Trigger dialog sql tab
|
||||
:align: center
|
||||
|
||||
The example demonstrates creating a compound trigger named *test_ct*.
|
||||
|
||||
* Click the *Info* button (i) to access online help.
|
||||
* Click the *Save* button to save work.
|
||||
* Click the *Cancel* button to exit without saving work.
|
||||
* Click the *Reset* button to restore configuration parameters.
|
BIN
docs/en_US/images/compound_trigger_code.png
Normal file
After Width: | Height: | Size: 141 KiB |
BIN
docs/en_US/images/compound_trigger_events.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
docs/en_US/images/compound_trigger_general.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
docs/en_US/images/compound_trigger_sql.png
Normal file
After Width: | Height: | Size: 92 KiB |
@@ -17,6 +17,7 @@ node, and select *Create Cast...*
|
||||
|
||||
check_dialog
|
||||
column_dialog
|
||||
compound_trigger_dialog
|
||||
exclusion_constraint_dialog
|
||||
foreign_key_dialog
|
||||
index_dialog
|
||||
|
@@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #4144 <https://redmine.postgresql.org/issues/4144>`_ - Add support of Compound Triggers for EPAS 12+.
|
||||
| `Issue #4333 <https://redmine.postgresql.org/issues/4333>`_ - Add support for planner support functions in PostgreSQL 12+ functions.
|
||||
| `Issue #4334 <https://redmine.postgresql.org/issues/4334>`_ - Add support for generated columns in Postgres 12+.
|
||||
| `Issue #4540 <https://redmine.postgresql.org/issues/4540>`_ - Use the full tab space for CodeMirror instances on dialogues where appropriate.
|
||||
@@ -43,4 +44,5 @@ Bug fixes
|
||||
| `Issue #4552 <https://redmine.postgresql.org/issues/4552>`_ - Fix some errors thrown on the JS console when dragging text in the Query Tool.
|
||||
| `Issue #4559 <https://redmine.postgresql.org/issues/4559>`_ - Ensure triggers should be updated properly for EPAS server.
|
||||
| `Issue #4565 <https://redmine.postgresql.org/issues/4565>`_ - Fix the reverse engineered SQL for trigger functions with the WINDOW option selected.
|
||||
| `Issue #4578 <https://redmine.postgresql.org/issues/4578>`_ - Ensure enable trigger menu should be visible when trigger is disabled.
|
||||
| `Issue #4581 <https://redmine.postgresql.org/issues/4581>`_ - Ensure the comment on a Primary Key constraint can be edited under the Table node.
|
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#efa539;}.cls-2{fill:#2f91a3;}</style></defs><title>coll_compound_trigger</title><g id="_10" data-name="10"><path class="cls-1" d="M2.75,12.5H4.82l0,1.7a.51.51,0,0,0,.31.47.65.65,0,0,0,.19,0,.5.5,0,0,0,.35-.14l2.51-2.42a.53.53,0,0,0,.15-.37H2A.74.74,0,0,0,2.75,12.5Z"/><path class="cls-2" d="M8.3,11.52a.5.5,0,0,0-.13-.34L5.75,8.68a.51.51,0,0,0-.55-.12A.48.48,0,0,0,4.89,9l0,1.72H2.76a.74.74,0,0,0-.75.75v0Z"/><path class="cls-1" d="M2.75,5.26H4.82L4.79,7a.5.5,0,0,0,.31.46.45.45,0,0,0,.19.05.5.5,0,0,0,.35-.14L8.15,4.91a.51.51,0,0,0,.15-.37H2A.74.74,0,0,0,2.75,5.26Z"/><path class="cls-2" d="M8.3,4.29A.48.48,0,0,0,8.17,4L5.75,1.44a.51.51,0,0,0-.55-.11.48.48,0,0,0-.31.45l0,1.73H2.76A.74.74,0,0,0,2,4.26v0Z"/><path class="cls-1" d="M8.44,8.64h2.08l0,1.71a.47.47,0,0,0,.3.46.46.46,0,0,0,.2,0,.49.49,0,0,0,.34-.14L13.84,8.3A.51.51,0,0,0,14,7.92H7.7A.75.75,0,0,0,8.44,8.64Z"/><path class="cls-2" d="M14,7.67a.5.5,0,0,0-.13-.34L11.44,4.82a.51.51,0,0,0-.55-.11.49.49,0,0,0-.31.45l0,1.73H8.45a.74.74,0,0,0-.75.75v0Z"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#2f91a3;}.cls-2{fill:#efa539;}.cls-3{fill:none;stroke:#d0021b;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}</style></defs><title>compud_trigger_disable</title><g id="_10" data-name="10"><path class="cls-1" d="M13,7.74a.5.5,0,0,0-.13-.25L8.79,3.22a.51.51,0,0,0-.55-.12.49.49,0,0,0-.31.46L7.87,6.77H3.94a1,1,0,0,0-1,1Z"/><path class="cls-2" d="M3,8.24a1,1,0,0,0,1,1H7.84l0,3.19a.47.47,0,0,0,.3.46.45.45,0,0,0,.2,0,.45.45,0,0,0,.34-.14l4.28-4.12A.52.52,0,0,0,13,8.21H3Z"/><line class="cls-3" x1="12.91" y1="2.46" x2="9.91" y2="5.46"/><line class="cls-3" x1="12.91" y1="5.46" x2="9.91" y2="2.46"/></g></svg>
|
After Width: | Height: | Size: 706 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#2f91a3;}.cls-2{fill:#efa539;}</style></defs><title>compund_trigger</title><g id="_10" data-name="10"><path class="cls-1" d="M13,7.74a.5.5,0,0,0-.13-.25L8.79,3.22a.51.51,0,0,0-.55-.12.49.49,0,0,0-.31.46L7.87,6.77H3.94a1,1,0,0,0-1,1Z"/><path class="cls-2" d="M3,8.24a1,1,0,0,0,1,1H7.84l0,3.19a.47.47,0,0,0,.3.46.45.45,0,0,0,.2,0,.45.45,0,0,0,.34-.14l4.28-4.12A.52.52,0,0,0,13,8.21H3Z"/></g></svg>
|
After Width: | Height: | Size: 480 B |
@@ -0,0 +1,412 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
define('pgadmin.node.compound_trigger', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
|
||||
'pgadmin.backform', 'pgadmin.alertifyjs',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify,
|
||||
SchemaChildTreeNode
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-compound_trigger']) {
|
||||
pgAdmin.Browser.Nodes['coll-compound_trigger'] =
|
||||
pgAdmin.Browser.Collection.extend({
|
||||
node: 'compound_trigger',
|
||||
label: gettext('Compound Triggers'),
|
||||
type: 'coll-compound_trigger',
|
||||
columns: ['name', 'description'],
|
||||
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
});
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['compound_trigger']) {
|
||||
pgAdmin.Browser.Nodes['compound_trigger'] = pgBrowser.Node.extend({
|
||||
parent_type: ['table', 'view', 'partition'],
|
||||
collection_type: ['coll-table', 'coll-view'],
|
||||
type: 'compound_trigger',
|
||||
label: gettext('Compound Trigger'),
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
width: pgBrowser.stdW.sm + 'px',
|
||||
sqlAlterHelp: 'sql-altertcompoundtrigger.html',
|
||||
sqlCreateHelp: 'sql-createcompoundtrigger.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'compound_trigger_dialog.html'}),
|
||||
Init: function() {
|
||||
/* Avoid mulitple registration of menus */
|
||||
if (this.initialized)
|
||||
return;
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
pgBrowser.add_menus([{
|
||||
name: 'create_compound_trigger_on_coll', node: 'coll-compound_trigger', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
||||
enable: 'canCreate',
|
||||
},{
|
||||
name: 'create_compound_trigger', node: 'compound_trigger', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
||||
enable: 'canCreate',
|
||||
},{
|
||||
name: 'create_compound_trigger_onTable', node: 'table', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
||||
enable: 'canCreate',
|
||||
},{
|
||||
name: 'create_compound_trigger_onPartition', node: 'partition', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
||||
enable: 'canCreate',
|
||||
},{
|
||||
name: 'enable_compound_trigger', node: 'compound_trigger', module: this,
|
||||
applies: ['object', 'context'], callback: 'enable_compound_trigger',
|
||||
category: 'connect', priority: 3, label: gettext('Enable compound trigger'),
|
||||
icon: 'fa fa-check', enable : 'canCreate_with_compound_trigger_enable',
|
||||
},{
|
||||
name: 'disable_compound_trigger', node: 'compound_trigger', module: this,
|
||||
applies: ['object', 'context'], callback: 'disable_compound_trigger',
|
||||
category: 'drop', priority: 3, label: gettext('Disable compound trigger'),
|
||||
icon: 'fa fa-times', enable : 'canCreate_with_compound_trigger_disable',
|
||||
},{
|
||||
name: 'create_compound_trigger_onView', node: 'view', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Compound Trigger...'),
|
||||
icon: 'wcTabIcon icon-compound_trigger', data: {action: 'create', check: true},
|
||||
enable: 'canCreate',
|
||||
},
|
||||
]);
|
||||
},
|
||||
callbacks: {
|
||||
/* Enable compound trigger */
|
||||
enable_compound_trigger: function(args) {
|
||||
var input = args || {},
|
||||
obj = this,
|
||||
t = pgBrowser.tree,
|
||||
i = input.item || t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
var data = d;
|
||||
$.ajax({
|
||||
url: obj.generate_url(i, 'enable' , d, true),
|
||||
type:'PUT',
|
||||
data: {'enable' : true},
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(function(res) {
|
||||
if (res.success == 1) {
|
||||
alertify.success(res.info);
|
||||
t.removeIcon(i);
|
||||
data.icon = 'icon-compound_trigger';
|
||||
t.addIcon(i, {icon: data.icon});
|
||||
t.unload(i);
|
||||
t.setInode(false);
|
||||
t.deselect(i);
|
||||
// Fetch updated data from server
|
||||
setTimeout(function() {
|
||||
t.select(i);
|
||||
}, 10);
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, error) {
|
||||
alertify.pgRespErrorNotify(xhr, error);
|
||||
t.unload(i);
|
||||
});
|
||||
},
|
||||
/* Disable compound trigger */
|
||||
disable_compound_trigger: function(args) {
|
||||
var input = args || {},
|
||||
obj = this,
|
||||
t = pgBrowser.tree,
|
||||
i = input.item || t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
var data = d;
|
||||
$.ajax({
|
||||
url: obj.generate_url(i, 'enable' , d, true),
|
||||
type:'PUT',
|
||||
data: {'enable' : false},
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(function(res) {
|
||||
if (res.success == 1) {
|
||||
alertify.success(res.info);
|
||||
t.removeIcon(i);
|
||||
data.icon = 'icon-compound_trigger-bad';
|
||||
t.addIcon(i, {icon: data.icon});
|
||||
t.unload(i);
|
||||
t.setInode(false);
|
||||
t.deselect(i);
|
||||
// Fetch updated data from server
|
||||
setTimeout(function() {
|
||||
t.select(i);
|
||||
}, 10);
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, error) {
|
||||
alertify.pgRespErrorNotify(xhr, error, gettext('Disable compound trigger failed'));
|
||||
t.unload(i);
|
||||
});
|
||||
},
|
||||
},
|
||||
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
idAttribute: 'oid',
|
||||
defaults: {
|
||||
name: undefined,
|
||||
},
|
||||
schema: [{
|
||||
id: 'name', label: gettext('Name'), cell: 'string',
|
||||
type: 'text', disabled: 'inSchema',
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string',
|
||||
type: 'int', disabled: true, mode: ['properties'],
|
||||
},{
|
||||
id: 'is_enable_trigger', label: gettext('Trigger enabled?'),
|
||||
type: 'switch', disabled: 'inSchema', mode: ['edit', 'properties'],
|
||||
},{
|
||||
type: 'nested', control: 'fieldset', mode: ['create','edit', 'properties'],
|
||||
label: gettext('FOR Events'), group: gettext('Events'), contentClass: 'row',
|
||||
schema:[{
|
||||
id: 'evnt_insert', label: gettext('INSERT'),
|
||||
type: 'switch', mode: ['create','edit', 'properties'],
|
||||
group: gettext('FOR Events'),
|
||||
extraToggleClasses: 'pg-el-sm-6',
|
||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
||||
disabled: function(m) {
|
||||
var evn_insert = m.get('evnt_insert');
|
||||
if (!_.isUndefined(evn_insert) && m.node_info['server']['server_type'] == 'ppas')
|
||||
return false;
|
||||
return m.inSchemaWithModelCheck.apply(this, [m]);
|
||||
},
|
||||
},{
|
||||
id: 'evnt_update', label: gettext('UPDATE'),
|
||||
type: 'switch', mode: ['create','edit', 'properties'],
|
||||
group: gettext('FOR Events'),
|
||||
extraToggleClasses: 'pg-el-sm-6',
|
||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
||||
disabled: function(m) {
|
||||
var evn_update = m.get('evnt_update');
|
||||
if (!_.isUndefined(evn_update) && m.node_info['server']['server_type'] == 'ppas')
|
||||
return false;
|
||||
return m.inSchemaWithModelCheck.apply(this, [m]);
|
||||
},
|
||||
},{
|
||||
id: 'evnt_delete', label: gettext('DELETE'),
|
||||
type: 'switch', mode: ['create','edit', 'properties'],
|
||||
group: gettext('FOR Events'),
|
||||
extraToggleClasses: 'pg-el-sm-6',
|
||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
||||
disabled: function(m) {
|
||||
var evn_delete = m.get('evnt_delete');
|
||||
if (!_.isUndefined(evn_delete) && m.node_info['server']['server_type'] == 'ppas')
|
||||
return false;
|
||||
return m.inSchemaWithModelCheck.apply(this, [m]);
|
||||
},
|
||||
}],
|
||||
},{
|
||||
id: 'whenclause', label: gettext('When'),
|
||||
type: 'text', disabled: 'inSchemaWithModelCheck',
|
||||
mode: ['create', 'edit', 'properties'],
|
||||
control: 'sql-field', visible: true, group: gettext('Events'),
|
||||
},{
|
||||
id: 'columns', label: gettext('Columns'), url: 'nodes',
|
||||
control: 'node-list-by-name', cache_node: 'column', type: 'array',
|
||||
select2: {'multiple': true},
|
||||
deps: ['evnt_update'], node: 'column', group: gettext('Events'),
|
||||
disabled: function(m) {
|
||||
if(this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
//Disable in edit mode
|
||||
if (!m.isNew()) {
|
||||
return true;
|
||||
}
|
||||
// Enable column only if update event is set true
|
||||
var isUpdate = m.get('evnt_update');
|
||||
if(!_.isUndefined(isUpdate) && isUpdate) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},{
|
||||
id: 'prosrc', label: gettext('Code'), group: gettext('Code'),
|
||||
type: 'text', mode: ['create', 'edit'],
|
||||
tabPanelCodeClass: 'sql-code-control',
|
||||
control: Backform.SqlCodeControl,
|
||||
disabled: function(m) {
|
||||
if(m.isNew()) {
|
||||
var code = m.getCodeTemplate();
|
||||
setTimeout(function() {
|
||||
m.set('prosrc', code);
|
||||
}, 10);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},{
|
||||
id: 'is_sys_trigger', label: gettext('System trigger?'), cell: 'string',
|
||||
type: 'switch', disabled: 'inSchemaWithModelCheck', mode: ['properties'],
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline', mode: ['properties', 'create', 'edit'],
|
||||
disabled: 'inSchema',
|
||||
}],
|
||||
validate: function(keys) {
|
||||
var msg;
|
||||
this.errorModel.clear();
|
||||
|
||||
// If nothing to validate
|
||||
if (keys && keys.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(_.isUndefined(this.get('name'))
|
||||
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Name cannot be empty.');
|
||||
this.errorModel.set('name', msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
if(!this.get('evnt_truncate') && !this.get('evnt_delete') &&
|
||||
!this.get('evnt_update') && !this.get('evnt_insert')) {
|
||||
msg = gettext('Specify at least one event.');
|
||||
this.errorModel.set('evnt_truncate', ' ');
|
||||
this.errorModel.set('evnt_delete', ' ');
|
||||
this.errorModel.set('evnt_update', ' ');
|
||||
this.errorModel.set('evnt_insert', msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
if(_.isUndefined(this.get('prosrc'))
|
||||
|| String(this.get('prosrc')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Code cannot be empty.');
|
||||
this.errorModel.set('prosrc', msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
// This function returns the code template for compound trigger
|
||||
getCodeTemplate: function () {
|
||||
return gettext('-- Enter any global declarations below:\n\n' +
|
||||
'-- BEFORE STATEMENT block. Delete if not required.\n' +
|
||||
'BEFORE STATEMENT IS\n' +
|
||||
' -- Enter any local declarations here\n' +
|
||||
'BEGIN\n' +
|
||||
' -- Enter any required code here\n' +
|
||||
'END;\n\n' +
|
||||
'-- AFTER STATEMENT block. Delete if not required.\n' +
|
||||
'AFTER STATEMENT IS\n' +
|
||||
' -- Enter any local declarations here\n' +
|
||||
'BEGIN\n' +
|
||||
' -- Enter any required code here\n' +
|
||||
'END;\n\n' +
|
||||
'-- BEFORE EACH ROW block. Delete if not required.\n' +
|
||||
'BEFORE EACH ROW IS\n' +
|
||||
' -- Enter any local declarations here\n' +
|
||||
'BEGIN\n' +
|
||||
' -- Enter any required code here\n' +
|
||||
'END;\n\n' +
|
||||
'-- AFTER EACH ROW block. Delete if not required.\n' +
|
||||
'AFTER EACH ROW IS\n' +
|
||||
' -- Enter any local declarations here\n' +
|
||||
'BEGIN\n' +
|
||||
' -- Enter any required code here\n' +
|
||||
'END;');
|
||||
},
|
||||
// We will check if we are under schema node & in 'create' mode
|
||||
inSchema: function() {
|
||||
if(this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// We will check if we are under schema node & in 'create' mode
|
||||
inSchemaWithModelCheck: function(m) {
|
||||
if(this.node_info && 'schema' in this.node_info) {
|
||||
// We will disable control if it's in 'edit' mode
|
||||
if (m.isNew()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// Checks weather to enable/disable control
|
||||
inSchemaWithColumnCheck: function(m) {
|
||||
if(this.node_info && 'schema' in this.node_info) {
|
||||
// We will disable control if it's system columns
|
||||
// ie: it's position is less then 1
|
||||
if (m.isNew()) {
|
||||
return false;
|
||||
} else {
|
||||
// if we are in edit mode
|
||||
if (!_.isUndefined(m.get('attnum')) && m.get('attnum') >= 1 ) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var treeData = this.getTreeNodeHierarchy(item),
|
||||
server = treeData['server'];
|
||||
|
||||
if (server && (server.server_type === 'pg' || server.version < 120000))
|
||||
return false;
|
||||
|
||||
// If it is catalog then don't allow user to create package
|
||||
if (treeData['catalog'] != undefined)
|
||||
return false;
|
||||
|
||||
// by default we want to allow create menu
|
||||
return true;
|
||||
},
|
||||
// Check to whether trigger is disable ?
|
||||
canCreate_with_compound_trigger_enable: function(itemData, item, data) {
|
||||
return itemData.icon === 'icon-compound_trigger-bad' &&
|
||||
this.canCreate.apply(this, [itemData, item, data]);
|
||||
},
|
||||
// Check to whether trigger is enable ?
|
||||
canCreate_with_compound_trigger_disable: function(itemData, item, data) {
|
||||
return itemData.icon === 'icon-compound_trigger' &&
|
||||
this.canCreate.apply(this, [itemData, item, data]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return pgBrowser.Nodes['compound_trigger'];
|
||||
});
|
@@ -0,0 +1,23 @@
|
||||
.icon-coll-compound_trigger {
|
||||
background-image: url('{{ url_for('NODE-compound_trigger.static', filename='img/coll-compound_trigger.svg' )}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px !important;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-compound_trigger {
|
||||
background-image: url('{{ url_for('NODE-compound_trigger.static', filename='img/compound_trigger.svg') }}') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 20px !important;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-compound_trigger-bad {
|
||||
background-image: url('{{ url_for('NODE-compound_trigger.static', filename='img/compound_trigger-bad.svg') }}') !important;
|
||||
background-size: 20px !important;
|
||||
border-radius: 10px
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
|
||||
|
||||
class CompoundTriggersTestGenerator(BaseTestGenerator):
|
||||
|
||||
def runTest(self):
|
||||
return []
|
@@ -0,0 +1,26 @@
|
||||
-- Compound Trigger: test_compound_trigger_$%{}[]()&*^!@"'`\/#
|
||||
|
||||
-- DROP TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#" ON testschema.table_for_compound_trigger;
|
||||
|
||||
CREATE OR REPLACE TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#"
|
||||
FOR INSERT OR UPDATE
|
||||
ON testschema.table_for_compound_trigger
|
||||
WHEN ((new.id < 100))
|
||||
COMPOUND TRIGGER
|
||||
var character varying(20) DEFAULT 'Global_var';
|
||||
|
||||
AFTER STATEMENT IS
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('After Statement: ' || var);
|
||||
var := 'AFTER STATEMENT';
|
||||
END;
|
||||
|
||||
AFTER EACH ROW IS
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('After each row: ' || var);
|
||||
var := 'AFTER EACH ROW';
|
||||
END;
|
||||
END "test_compound_trigger_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
COMMENT ON TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#" ON testschema.table_for_compound_trigger
|
||||
IS 'This is test comment.';
|
@@ -0,0 +1,13 @@
|
||||
-- Compound Trigger: test_compound_trigger_$%{}[]()&*^!@"'`\/#
|
||||
|
||||
-- DROP TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#" ON testschema.table_for_compound_trigger;
|
||||
|
||||
CREATE OR REPLACE TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#"
|
||||
FOR INSERT OR DELETE
|
||||
ON testschema.table_for_compound_trigger
|
||||
COMPOUND TRIGGER
|
||||
BEFORE STATEMENT IS
|
||||
BEGIN
|
||||
SELECT 1;
|
||||
END;
|
||||
END "test_compound_trigger_$%{}[]()&*^!@""'`\/#";
|
@@ -0,0 +1,22 @@
|
||||
-- Compound Trigger: test_compound_trigger_$%{}[]()&*^!@"'`\/#
|
||||
|
||||
-- DROP TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#" ON testschema.table_for_compound_trigger;
|
||||
|
||||
CREATE OR REPLACE TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#"
|
||||
FOR INSERT OR UPDATE OF id, name
|
||||
ON testschema.table_for_compound_trigger
|
||||
COMPOUND TRIGGER
|
||||
var character varying(20) DEFAULT 'Global_var';
|
||||
|
||||
BEFORE STATEMENT IS
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('Before Statement: ' || var);
|
||||
var := 'BEFORE STATEMENT';
|
||||
END;
|
||||
|
||||
BEFORE EACH ROW IS
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('Before each row: ' || var);
|
||||
var := 'BEFORE EACH ROW';
|
||||
END;
|
||||
END "test_compound_trigger_$%{}[]()&*^!@""'`\/#";
|
@@ -0,0 +1,23 @@
|
||||
-- Compound Trigger: test_compound_trigger_$%{}[]()&*^!@"'`\/#
|
||||
|
||||
-- DROP TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#" ON testschema.table_for_compound_trigger;
|
||||
|
||||
CREATE OR REPLACE TRIGGER "test_compound_trigger_$%{}[]()&*^!@""'`\/#"
|
||||
FOR INSERT
|
||||
ON testschema.table_for_compound_trigger
|
||||
WHEN ((new.id < 100))
|
||||
COMPOUND TRIGGER
|
||||
var character varying(20) DEFAULT 'Global_var';
|
||||
|
||||
BEFORE STATEMENT IS
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('Before Statement: ' || var);
|
||||
var := 'BEFORE STATEMENT';
|
||||
END;
|
||||
|
||||
BEFORE EACH ROW IS
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('Before each row: ' || var);
|
||||
var := 'BEFORE EACH ROW';
|
||||
END;
|
||||
END "test_compound_trigger_$%{}[]()&*^!@""'`\/#";
|
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Table",
|
||||
"endpoint": "NODE-table.obj",
|
||||
"sql_endpoint": "NODE-table.sql_id",
|
||||
"data": {
|
||||
"name": "table_for_compound_trigger",
|
||||
"columns": [{
|
||||
"name": "id",
|
||||
"cltype": "integer",
|
||||
"is_primary_key": true
|
||||
}, {
|
||||
"name": "name",
|
||||
"cltype": "text"
|
||||
}],
|
||||
"is_partitioned": false,
|
||||
"schema": "testschema",
|
||||
"spcname": "pg_default"
|
||||
},
|
||||
"store_table_id": true
|
||||
}, {
|
||||
"type": "create",
|
||||
"name": "Create compound trigger for insert or delete",
|
||||
"endpoint": "NODE-compound_trigger.obj",
|
||||
"sql_endpoint": "NODE-compound_trigger.sql_id",
|
||||
"data": {
|
||||
"name": "test_compound_trigger_$%{}[]()&*^!@\"'`\\/#",
|
||||
"prosrc": "BEFORE STATEMENT IS\nBEGIN\n\tSELECT 1;\nEND;",
|
||||
"evnt_insert": true,
|
||||
"evnt_update": false,
|
||||
"evnt_delete": true,
|
||||
"columns": ["id", "name"]
|
||||
},
|
||||
"expected_sql_file": "create_for_insert_delete.sql"
|
||||
}, {
|
||||
"type": "delete",
|
||||
"name": "Drop Compound Trigger",
|
||||
"endpoint": "NODE-compound_trigger.delete_id",
|
||||
"data": {
|
||||
"name": "test_compound_trigger_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}, {
|
||||
"type": "create",
|
||||
"name": "Create compound trigger for insert with when condition",
|
||||
"endpoint": "NODE-compound_trigger.obj",
|
||||
"sql_endpoint": "NODE-compound_trigger.sql_id",
|
||||
"data": {
|
||||
"name": "test_compound_trigger_$%{}[]()&*^!@\"'`\\/#",
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\nBEFORE STATEMENT IS\nBEGIN\n\tDBMS_OUTPUT.PUT_LINE('Before Statement: ' || var);\n\tvar := 'BEFORE STATEMENT';\nEND;\n\nBEFORE EACH ROW IS\nBEGIN\n\tDBMS_OUTPUT.PUT_LINE('Before each row: ' || var);\n\tvar := 'BEFORE EACH ROW';\nEND;",
|
||||
"evnt_insert": true,
|
||||
"evnt_update": false,
|
||||
"evnt_delete": false,
|
||||
"whenclause": "NEW.id < 100"
|
||||
},
|
||||
"expected_sql_file": "create_for_insert_with_when.sql"
|
||||
}, {
|
||||
"type": "alter",
|
||||
"name": "Alter event, comment and code",
|
||||
"endpoint": "NODE-compound_trigger.obj_id",
|
||||
"sql_endpoint": "NODE-compound_trigger.sql_id",
|
||||
"data": {
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\nAFTER STATEMENT IS\nBEGIN\n\tDBMS_OUTPUT.PUT_LINE('After Statement: ' || var);\n\tvar := 'AFTER STATEMENT';\nEND;\n\nAFTER EACH ROW IS\nBEGIN\n\tDBMS_OUTPUT.PUT_LINE('After each row: ' || var);\n\tvar := 'AFTER EACH ROW';\nEND;",
|
||||
"evnt_update": true,
|
||||
"description": "This is test comment."
|
||||
},
|
||||
"expected_sql_file": "alter_event_comment_code.sql"
|
||||
}, {
|
||||
"type": "delete",
|
||||
"name": "Drop Compound Trigger",
|
||||
"endpoint": "NODE-compound_trigger.delete_id",
|
||||
"data": {
|
||||
"name": "test_compound_trigger_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}, {
|
||||
"type": "create",
|
||||
"name": "Create compound trigger for insert or update on columns",
|
||||
"endpoint": "NODE-compound_trigger.obj",
|
||||
"sql_endpoint": "NODE-compound_trigger.sql_id",
|
||||
"data": {
|
||||
"name": "test_compound_trigger_$%{}[]()&*^!@\"'`\\/#",
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\nBEFORE STATEMENT IS\nBEGIN\n\tDBMS_OUTPUT.PUT_LINE('Before Statement: ' || var);\n\tvar := 'BEFORE STATEMENT';\nEND;\n\nBEFORE EACH ROW IS\nBEGIN\n\tDBMS_OUTPUT.PUT_LINE('Before each row: ' || var);\n\tvar := 'BEFORE EACH ROW';\nEND;",
|
||||
"evnt_insert": true,
|
||||
"evnt_update": true,
|
||||
"evnt_delete": false,
|
||||
"columns": ["id", "name"]
|
||||
},
|
||||
"expected_sql_file": "create_for_insert_update_on_columns.sql"
|
||||
}, {
|
||||
"type": "delete",
|
||||
"name": "Drop Compound Trigger",
|
||||
"endpoint": "NODE-compound_trigger.delete_id",
|
||||
"data": {
|
||||
"name": "test_compound_trigger_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from pgadmin.utils import server_utils as server_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||
import utils as tables_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
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
class CompoundTriggersAddTestCase(BaseTestGenerator):
|
||||
"""This class will add new compound trigger under table node."""
|
||||
skip_on_database = ['gpdb']
|
||||
scenarios = [
|
||||
('Create compound trigger for insert and delete',
|
||||
dict(
|
||||
url='/browser/compound_trigger/obj/',
|
||||
data={
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\n"
|
||||
"BEFORE STATEMENT IS\nBEGIN\n "
|
||||
"DBMS_OUTPUT.PUT_LINE('Before Statement: ' || var)"
|
||||
";\n var := 'BEFORE STATEMENT';\nEND;\n\nBEFORE "
|
||||
"EACH ROW IS\nBEGIN\n DBMS_OUTPUT.PUT_LINE('"
|
||||
"Before each row: ' || var);\n var := 'BEFORE "
|
||||
"EACH ROW';\nEND;",
|
||||
"evnt_insert": True,
|
||||
"evnt_update": False,
|
||||
"evnt_delete": True
|
||||
}
|
||||
)),
|
||||
('Create compound trigger for insert with when condition',
|
||||
dict(
|
||||
url='/browser/compound_trigger/obj/',
|
||||
data={
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\n"
|
||||
"BEFORE STATEMENT IS\nBEGIN\n "
|
||||
"DBMS_OUTPUT.PUT_LINE('Before Statement: ' || var)"
|
||||
";\n var := 'BEFORE STATEMENT';\nEND;\n\nBEFORE "
|
||||
"EACH ROW IS\nBEGIN\n DBMS_OUTPUT.PUT_LINE('"
|
||||
"Before each row: ' || var);\n var := 'BEFORE "
|
||||
"EACH ROW';\nEND;",
|
||||
"evnt_insert": True,
|
||||
"evnt_update": False,
|
||||
"evnt_delete": False,
|
||||
"whenclause": "NEW.id < 100"
|
||||
}
|
||||
)),
|
||||
('Create compound trigger for insert or update on columns',
|
||||
dict(
|
||||
url='/browser/compound_trigger/obj/',
|
||||
data={
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\n"
|
||||
"BEFORE STATEMENT IS\nBEGIN\n "
|
||||
"DBMS_OUTPUT.PUT_LINE('Before Statement: ' || var)"
|
||||
";\n var := 'BEFORE STATEMENT';\nEND;\n\nBEFORE "
|
||||
"EACH ROW IS\nBEGIN\n DBMS_OUTPUT.PUT_LINE('"
|
||||
"Before each row: ' || var);\n var := 'BEFORE "
|
||||
"EACH ROW';\nEND;",
|
||||
"evnt_insert": True,
|
||||
"evnt_update": True,
|
||||
"columns": ["id", "name"]
|
||||
}
|
||||
)),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(CompoundTriggersAddTestCase, self).setUp()
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
schema_info = parent_node_dict["schema"][-1]
|
||||
self.server_id = schema_info["server_id"]
|
||||
self.db_id = schema_info["db_id"]
|
||||
server_con = server_utils.connect_server(self, self.server_id)
|
||||
if server_con:
|
||||
if "type" in server_con["data"]:
|
||||
if server_con["data"]["type"] == "pg":
|
||||
message = "Compound Triggers are not supported by PG."
|
||||
self.skipTest(message)
|
||||
elif server_con["data"]["type"] == "ppas" \
|
||||
and server_con["data"]["version"] < 120000:
|
||||
message = "Compound Triggers are not supported by " \
|
||||
"EPAS server less than 12"
|
||||
self.skipTest(message)
|
||||
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception("Could not connect to database to add a trigger.")
|
||||
self.schema_id = schema_info["schema_id"]
|
||||
self.schema_name = schema_info["schema_name"]
|
||||
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 a compound trigger.")
|
||||
self.table_name = \
|
||||
"table_compound_trigger_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will create compound trigger under table node."""
|
||||
trigger_name = \
|
||||
"test_compound_trigger_add_%s" % (str(uuid.uuid4())[1:8])
|
||||
|
||||
self.data.update({"name": trigger_name})
|
||||
|
||||
response = self.tester.post(
|
||||
"{0}{1}/{2}/{3}/{4}/{5}/".format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id,
|
||||
self.schema_id, self.table_id),
|
||||
data=json.dumps(self.data),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@@ -0,0 +1,98 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
|
||||
from pgadmin.utils import server_utils as server_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||
import utils as tables_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
|
||||
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 compound_triggers_utils
|
||||
|
||||
|
||||
class CompoundTriggersDeleteTestCase(BaseTestGenerator):
|
||||
"""This class will delete compound trigger under table node."""
|
||||
skip_on_database = ['gpdb']
|
||||
scenarios = [
|
||||
('Delete compound trigger',
|
||||
dict(url='/browser/compound_trigger/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(CompoundTriggersDeleteTestCase, self).setUp()
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
schema_info = parent_node_dict["schema"][-1]
|
||||
self.server_id = schema_info["server_id"]
|
||||
self.db_id = schema_info["db_id"]
|
||||
server_con = server_utils.connect_server(self, self.server_id)
|
||||
if server_con:
|
||||
if "type" in server_con["data"]:
|
||||
if server_con["data"]["type"] == "pg":
|
||||
message = "Compound Triggers are not supported by PG."
|
||||
self.skipTest(message)
|
||||
elif server_con["data"]["type"] == "ppas" \
|
||||
and server_con["data"]["version"] < 120000:
|
||||
message = "Compound Triggers are not supported by " \
|
||||
"EPAS server less than 12"
|
||||
self.skipTest(message)
|
||||
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception(
|
||||
"Could not connect to database to delete a compound trigger.")
|
||||
self.schema_id = schema_info["schema_id"]
|
||||
self.schema_name = schema_info["schema_name"]
|
||||
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 delete a compound trigger.")
|
||||
self.table_name = \
|
||||
"table_compound_trigger_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name)
|
||||
|
||||
self.trigger_name = \
|
||||
"test_compound_trigger_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.trigger_id = \
|
||||
compound_triggers_utils.create_compound_trigger(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name,
|
||||
self.trigger_name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will update trigger under table node."""
|
||||
trigger_response = \
|
||||
compound_triggers_utils.verify_compound_trigger(self.server,
|
||||
self.db_name,
|
||||
self.trigger_name)
|
||||
if not trigger_response:
|
||||
raise Exception("Could not find the compound trigger to delete.")
|
||||
response = self.tester.delete(
|
||||
"{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id,
|
||||
self.schema_id, self.table_id,
|
||||
self.trigger_id),
|
||||
follow_redirects=True
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@@ -0,0 +1,112 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
import json
|
||||
|
||||
from pgadmin.utils import server_utils as server_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||
import utils as tables_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
|
||||
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 compound_triggers_utils
|
||||
|
||||
|
||||
class CompoundTriggersDeleteMultipleTestCase(BaseTestGenerator):
|
||||
"""This class will delete multiple compound triggers under table node."""
|
||||
skip_on_database = ['gpdb']
|
||||
scenarios = [
|
||||
('Delete multiple compound trigger',
|
||||
dict(url='/browser/compound_trigger/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(CompoundTriggersDeleteMultipleTestCase, self).setUp()
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
schema_info = parent_node_dict["schema"][-1]
|
||||
self.server_id = schema_info["server_id"]
|
||||
self.db_id = schema_info["db_id"]
|
||||
server_con = server_utils.connect_server(self, self.server_id)
|
||||
if server_con:
|
||||
if "type" in server_con["data"]:
|
||||
if server_con["data"]["type"] == "pg":
|
||||
message = "Compound Triggers are not supported by PG."
|
||||
self.skipTest(message)
|
||||
elif server_con["data"]["type"] == "ppas" \
|
||||
and server_con["data"]["version"] < 120000:
|
||||
message = "Compound Triggers are not supported by " \
|
||||
"EPAS server less than 12"
|
||||
self.skipTest(message)
|
||||
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception(
|
||||
"Could not connect to database to delete a compound trigger.")
|
||||
self.schema_id = schema_info["schema_id"]
|
||||
self.schema_name = schema_info["schema_name"]
|
||||
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 delete a compound trigger.")
|
||||
self.table_name = \
|
||||
"table_compound_trigger_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name)
|
||||
|
||||
self.trigger_name = \
|
||||
"test_trigger_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.trigger_name_1 = \
|
||||
"test_trigger_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.trigger_ids = [compound_triggers_utils.create_compound_trigger(
|
||||
self.server, self.db_name, self.schema_name, self.table_name,
|
||||
self.trigger_name),
|
||||
compound_triggers_utils.create_compound_trigger(
|
||||
self.server, self.db_name, self.schema_name, self.table_name,
|
||||
self.trigger_name_1)
|
||||
]
|
||||
|
||||
def runTest(self):
|
||||
"""This function will delete multiple compound trigger under
|
||||
table node."""
|
||||
trigger_response = \
|
||||
compound_triggers_utils.verify_compound_trigger(
|
||||
self.server, self.db_name, self.trigger_name)
|
||||
if not trigger_response:
|
||||
raise Exception("Could not find the compound trigger to delete.")
|
||||
|
||||
trigger_response = \
|
||||
compound_triggers_utils.verify_compound_trigger(
|
||||
self.server, self.db_name, self.trigger_name_1)
|
||||
if not trigger_response:
|
||||
raise Exception("Could not find the compound trigger to delete.")
|
||||
|
||||
data = {'ids': self.trigger_ids}
|
||||
response = self.tester.delete(
|
||||
"{0}{1}/{2}/{3}/{4}/{5}/".format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id,
|
||||
self.schema_id, self.table_id
|
||||
),
|
||||
follow_redirects=True,
|
||||
data=json.dumps(data),
|
||||
content_type='html/json'
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@@ -0,0 +1,134 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from pgadmin.utils import server_utils as server_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||
import utils as tables_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
|
||||
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 compound_triggers_utils
|
||||
|
||||
|
||||
class CompoundTriggersUpdateTestCase(BaseTestGenerator):
|
||||
"""This class will update compound trigger under table node."""
|
||||
skip_on_database = ['gpdb']
|
||||
scenarios = [
|
||||
('Update comment',
|
||||
dict(url='/browser/compound_trigger/obj/',
|
||||
data={"description": "This is test comment."}
|
||||
)),
|
||||
('Update event and code',
|
||||
dict(url='/browser/compound_trigger/obj/',
|
||||
data={
|
||||
"evnt_update": True,
|
||||
"prosrc": "var varchar2(20) := 'Global_var';\n\n"
|
||||
"AFTER STATEMENT IS\nBEGIN\n "
|
||||
"DBMS_OUTPUT.PUT_LINE('After Statement: ' || var)"
|
||||
";\n var := 'AFTER STATEMENT';\nEND;\n\nAFTER "
|
||||
"EACH ROW IS\nBEGIN\n DBMS_OUTPUT.PUT_LINE('"
|
||||
"After each row: ' || var);\n var := 'AFTER "
|
||||
"EACH ROW';\nEND;",
|
||||
})),
|
||||
('Enable compound trigger',
|
||||
dict(url='/browser/compound_trigger/obj/',
|
||||
data={"is_enable_trigger": True},
|
||||
disable_trigger=True
|
||||
)),
|
||||
('Disable compound trigger',
|
||||
dict(url='/browser/compound_trigger/obj/',
|
||||
data={"is_enable_trigger": False}
|
||||
)),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(CompoundTriggersUpdateTestCase, self).setUp()
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
schema_info = parent_node_dict["schema"][-1]
|
||||
self.server_id = schema_info["server_id"]
|
||||
self.db_id = schema_info["db_id"]
|
||||
server_con = server_utils.connect_server(self, self.server_id)
|
||||
if server_con:
|
||||
if "type" in server_con["data"]:
|
||||
if server_con["data"]["type"] == "pg":
|
||||
message = "Compound Triggers are not supported by PG."
|
||||
self.skipTest(message)
|
||||
elif server_con["data"]["type"] == "ppas" \
|
||||
and server_con["data"]["version"] < 120000:
|
||||
message = "Compound Triggers are not supported by " \
|
||||
"EPAS server less than 12"
|
||||
self.skipTest(message)
|
||||
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception(
|
||||
"Could not connect to database to update a compound trigger.")
|
||||
self.schema_id = schema_info["schema_id"]
|
||||
self.schema_name = schema_info["schema_name"]
|
||||
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 update a trigger.")
|
||||
self.table_name = \
|
||||
"table_compound_trigger_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name)
|
||||
|
||||
self.trigger_name = \
|
||||
"test_compound_trigger_update_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.trigger_id = \
|
||||
compound_triggers_utils.create_compound_trigger(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name,
|
||||
self.trigger_name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will update trigger under table node."""
|
||||
trigger_response = \
|
||||
compound_triggers_utils.verify_compound_trigger(self.server,
|
||||
self.db_name,
|
||||
self.trigger_name)
|
||||
if not trigger_response:
|
||||
raise Exception("Could not find the compound trigger to update.")
|
||||
|
||||
if hasattr(self, 'disable_trigger') and self.disable_trigger:
|
||||
compound_triggers_utils.enable_disable_compound_trigger(
|
||||
self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.table_name,
|
||||
self.trigger_name,
|
||||
False
|
||||
)
|
||||
|
||||
self.data.update({"id": self.trigger_id})
|
||||
response = self.tester.put(
|
||||
"{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id,
|
||||
self.schema_id, self.table_id,
|
||||
self.trigger_id),
|
||||
data=json.dumps(self.data),
|
||||
follow_redirects=True
|
||||
)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@@ -0,0 +1,137 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
def create_compound_trigger(server, db_name, schema_name, table_name,
|
||||
trigger_name):
|
||||
"""
|
||||
This function creates a column under provided table.
|
||||
:param server: server details
|
||||
:type server: dict
|
||||
:param db_name: database name
|
||||
:type db_name: str
|
||||
:param schema_name: schema name
|
||||
:type schema_name: str
|
||||
:param table_name: table name
|
||||
:type table_name: str
|
||||
:param trigger_name: trigger name
|
||||
:type trigger_name: str
|
||||
:param trigger_func_name: trigger function name
|
||||
:type trigger_func_name: str
|
||||
:return trigger_id: trigger id
|
||||
:rtype: int
|
||||
"""
|
||||
code = "var varchar2(20) := 'Global_var';\n\n BEFORE STATEMENT IS" \
|
||||
"\nBEGIN\n DBMS_OUTPUT.PUT_LINE('Before Statement: ' || var);" \
|
||||
"\n var := 'BEFORE STATEMENT';\nEND;\n\nBEFORE EACH ROW IS" \
|
||||
"\nBEGIN\n DBMS_OUTPUT.PUT_LINE('Before each row: ' || var);\n" \
|
||||
" var := 'BEFORE EACH ROW';\nEND;"
|
||||
|
||||
try:
|
||||
connection = utils.get_db_connection(db_name,
|
||||
server['username'],
|
||||
server['db_password'],
|
||||
server['host'],
|
||||
server['port'],
|
||||
server['sslmode'])
|
||||
old_isolation_level = connection.isolation_level
|
||||
connection.set_isolation_level(0)
|
||||
pg_cursor = connection.cursor()
|
||||
query = "CREATE OR REPLACE TRIGGER %s FOR INSERT ON %s.%s " \
|
||||
"COMPOUND TRIGGER %s END;" % (trigger_name, schema_name,
|
||||
table_name, code)
|
||||
pg_cursor.execute(query)
|
||||
connection.set_isolation_level(old_isolation_level)
|
||||
connection.commit()
|
||||
pg_cursor.execute("SELECT oid FROM pg_trigger where tgname='%s'" %
|
||||
trigger_name)
|
||||
trigger = pg_cursor.fetchone()
|
||||
trigger_id = ''
|
||||
if trigger:
|
||||
trigger_id = trigger[0]
|
||||
connection.close()
|
||||
return trigger_id
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
raise
|
||||
|
||||
|
||||
def verify_compound_trigger(server, db_name, trigger_name):
|
||||
"""
|
||||
This function verifies table exist in database or not.
|
||||
:param server: server details
|
||||
:type server: dict
|
||||
:param db_name: database name
|
||||
:type db_name: str
|
||||
:param trigger_name: column name
|
||||
:type trigger_name: str
|
||||
:return table: table record from database
|
||||
:rtype: tuple
|
||||
"""
|
||||
try:
|
||||
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 oid FROM pg_trigger where tgname='%s'" %
|
||||
trigger_name)
|
||||
trigger = pg_cursor.fetchone()
|
||||
connection.close()
|
||||
return trigger
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
raise
|
||||
|
||||
|
||||
def enable_disable_compound_trigger(server, db_name, schema_name, table_name,
|
||||
trigger_name, is_enable):
|
||||
"""
|
||||
This function is used to enable/disable trigger.
|
||||
:param server:
|
||||
:param db_name:
|
||||
:param schema_name:
|
||||
:param table_name:
|
||||
:param trigger_name:
|
||||
:param is_enable:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
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("BEGIN")
|
||||
if is_enable:
|
||||
query = "ALTER TABLE %s.%s ENABLE TRIGGER %s;" % (schema_name,
|
||||
table_name,
|
||||
trigger_name)
|
||||
else:
|
||||
query = "ALTER TABLE %s.%s DISABLE TRIGGER %s;" % (schema_name,
|
||||
table_name,
|
||||
trigger_name)
|
||||
|
||||
pg_cursor.execute(query)
|
||||
pg_cursor.execute("COMMIT")
|
||||
connection.close()
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
raise
|
@@ -0,0 +1,26 @@
|
||||
{### Set a flag which allows us to put OR between events ###}
|
||||
{% set or_flag = False %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
FOR {% if data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE{% if data.columns|length > 0 %} OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.whenclause %}
|
||||
WHEN {% if not data.oid %}({% endif %}{{ data.whenclause }}{% if not data.oid %}){% endif %}
|
||||
|
||||
{% endif %}
|
||||
COMPOUND TRIGGER
|
||||
{% if data.prosrc is defined %}{{ data.prosrc }}{% endif%}
|
||||
|
||||
END {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% if data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
@@ -0,0 +1,10 @@
|
||||
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgpackageoid != 0
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,22 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.tgtype, t.tgattr, relname,
|
||||
CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description,
|
||||
regexp_replace(regexp_replace(pg_get_triggerdef(t.oid),
|
||||
'CREATE TRIGGER (.*) FOR (.*) ON (.*) \nCOMPOUND TRIGGER (.*)\n', ''), '[\n]?END$', ''
|
||||
) AS prosrc,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \nCOMPOUND'), NULL) AS whenclause,
|
||||
{% if datlastsysoid %}
|
||||
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
|
||||
{% endif %}
|
||||
(CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
JOIN pg_class cl ON cl.oid=tgrelid
|
||||
JOIN pg_namespace na ON na.oid=relnamespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgpackageoid != 0
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,40 @@
|
||||
{% if data.name and o_data.name != data.name %}
|
||||
ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% endif %}
|
||||
{% if ((data.prosrc is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined) and (o_data.prosrc != data.prosrc or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update)) %}
|
||||
{% set or_flag = False %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
FOR {% if data.evnt_insert is not defined %}{% if o_data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% if data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% endif %}{% if data.evnt_delete is not defined %}{% if o_data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE{% if o_data.columns|length > 0 %} OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}{% else %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE{% if o_data.columns|length > 0 %} OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if o_data.whenclause %}
|
||||
WHEN {{ o_data.whenclause }}
|
||||
|
||||
{% endif %}
|
||||
COMPOUND TRIGGER
|
||||
{% if (data.prosrc is not defined) %}{{ o_data.prosrc }}{% else %}{{ data.prosrc }}{% endif %}
|
||||
|
||||
END {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% if data.description is not defined and o_data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS {{o_data.description|qtLiteral}};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if data.description is defined and o_data.description != data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
||||
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
|
||||
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
|
||||
{% endif %}
|
@@ -1,7 +1,7 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \\$trigger')) AS whenclause,
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause,
|
||||
-- We need to convert tgargs column bytea datatype to array datatype
|
||||
(string_to_array(encode(tgargs, 'escape'), E'\\000')::text[])[1:tgnargs] AS custom_tgargs,
|
||||
{% if datlastsysoid %}
|
@@ -0,0 +1,9 @@
|
||||
{#=============Checks if it is materialized view========#}
|
||||
{% if vid %}
|
||||
SELECT
|
||||
CASE WHEN c.relkind = 'm' THEN False ELSE True END As m_view
|
||||
FROM
|
||||
pg_class c
|
||||
WHERE
|
||||
c.oid = {{ vid }}::oid
|
||||
{% endif %}
|
@@ -0,0 +1 @@
|
||||
DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};
|
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
|
@@ -0,0 +1,6 @@
|
||||
SELECT att.attname as name
|
||||
FROM pg_attribute att
|
||||
WHERE att.attrelid = {{tid}}::oid
|
||||
AND att.attnum IN ({{ clist }})
|
||||
AND att.attisdropped IS FALSE
|
||||
ORDER BY att.attnum
|
@@ -0,0 +1,4 @@
|
||||
SELECT t.oid
|
||||
FROM pg_trigger t
|
||||
WHERE tgrelid = {{tid}}::OID
|
||||
AND tgname = {{data.name|qtLiteral}};
|
@@ -0,0 +1,5 @@
|
||||
SELECT nsp.nspname AS schema ,rel.relname AS table
|
||||
FROM pg_class rel
|
||||
JOIN pg_namespace nsp
|
||||
ON rel.relnamespace = nsp.oid::oid
|
||||
WHERE rel.oid = {{tid}}::oid
|
@@ -6,16 +6,16 @@ ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname,
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined) and o_data.lanname == 'edbspl' and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires)) %}
|
||||
{% set or_flag = False %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% if data.fires is defined %} {{data.fires}} {% else %}{{o_data.fires}}{% endif %} {% if data.evnt_insert is not defined %} {% if o_data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% if data.fires is defined %}{{data.fires}} {% else %}{{o_data.fires}} {% endif %}{% if data.evnt_insert is not defined %}{% if o_data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% endif %}{% if data.evnt_delete is not defined %}{% if o_data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% else %} {% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %} {%endif %}{% endif %}{% if data.evnt_truncate is not defined %}{% if o_data.evnt_truncate %}
|
||||
{% endif %}{% else %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_truncate is not defined %}{% if o_data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% else %} {% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %} {%endif %} {% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% endif %}{% else %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}{% else %} {% if data.evnt_update %}
|
||||
{% endif %}{% else %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \\$trigger')) AS whenclause,
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause,
|
||||
-- We need to convert tgargs column bytea datatype to array datatype
|
||||
(string_to_array(encode(tgargs, 'escape'), E'\\000')::text[])[1:tgnargs] AS custom_tgargs,
|
||||
{% if datlastsysoid %}
|
@@ -0,0 +1,5 @@
|
||||
SELECT t.oid
|
||||
FROM pg_trigger t
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgname = {{data.name|qtLiteral}};
|
@@ -0,0 +1,9 @@
|
||||
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,23 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause,
|
||||
-- We need to convert tgargs column bytea datatype to array datatype
|
||||
(string_to_array(encode(tgargs, 'escape'), E'\\000')::text[])[1:tgnargs] AS custom_tgargs,
|
||||
{% if datlastsysoid %}
|
||||
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
|
||||
{% endif %}
|
||||
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger,
|
||||
(CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
JOIN pg_class cl ON cl.oid=tgrelid
|
||||
JOIN pg_namespace na ON na.oid=relnamespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
|
||||
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,9 @@
|
||||
{## Alter index to use cluster type ##}
|
||||
{% if data.indisclustered %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
CLUSTER ON {{conn|qtIdent(data.name)}};
|
||||
{% endif %}
|
||||
{## Changes description ##}
|
||||
{% if data.description %}
|
||||
COMMENT ON INDEX {{conn|qtIdent(data.name)}}
|
||||
IS {{data.description|qtLiteral}};{% endif %}
|
@@ -0,0 +1,9 @@
|
||||
{#=============Checks if it is materialized view========#}
|
||||
{% if vid %}
|
||||
SELECT
|
||||
CASE WHEN c.relkind = 'm' THEN False ELSE True END As m_view
|
||||
FROM
|
||||
pg_class c
|
||||
WHERE
|
||||
c.oid = {{ vid }}::oid
|
||||
{% endif %}
|
@@ -0,0 +1,32 @@
|
||||
{### Set a flag which allows us to put OR between events ###}
|
||||
{% set or_flag = False %}
|
||||
{% if data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL' %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% else %}
|
||||
CREATE{% if data.is_constraint_trigger %} CONSTRAINT{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% endif %}
|
||||
{{data.fires}} {% if data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if data.columns|length > 0 %}OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.tgdeferrable %}
|
||||
DEFERRABLE{% if data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
{% endif %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %}
|
||||
{% if data.whenclause %}
|
||||
|
||||
WHEN ({{ data.whenclause }}){% endif %}
|
||||
|
||||
{% if data.prosrc is defined and
|
||||
(data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL') %}{{ data.prosrc }}{% else %}EXECUTE PROCEDURE {{ data.tfunction }}{% if data.tgargs %}({{ data.tgargs }}){% else %}(){% endif%}{% endif%};
|
||||
|
||||
{% if data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
@@ -0,0 +1 @@
|
||||
DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};
|
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
|
@@ -0,0 +1,6 @@
|
||||
SELECT att.attname as name
|
||||
FROM pg_attribute att
|
||||
WHERE att.attrelid = {{tid}}::oid
|
||||
AND att.attnum IN ({{ clist }})
|
||||
AND att.attisdropped IS FALSE
|
||||
ORDER BY att.attnum
|
@@ -0,0 +1,4 @@
|
||||
SELECT t.oid
|
||||
FROM pg_trigger t
|
||||
WHERE tgrelid = {{tid}}::OID
|
||||
AND tgname = {{data.name|qtLiteral}};
|
@@ -0,0 +1,5 @@
|
||||
SELECT nsp.nspname AS schema ,rel.relname AS table
|
||||
FROM pg_class rel
|
||||
JOIN pg_namespace nsp
|
||||
ON rel.relnamespace = nsp.oid::oid
|
||||
WHERE rel.oid = {{tid}}::oid
|
@@ -0,0 +1,15 @@
|
||||
SELECT quote_ident(nspname) || '.' || quote_ident(proname) AS tfunctions
|
||||
FROM pg_proc p, pg_namespace n, pg_language l
|
||||
WHERE p.pronamespace = n.oid
|
||||
AND p.prolang = l.oid
|
||||
-- PGOID_TYPE_TRIGGER = 2279
|
||||
AND l.lanname != 'edbspl' AND prorettype = 2279
|
||||
-- If Show SystemObjects is not true
|
||||
{% if not show_system_objects %}
|
||||
AND (nspname NOT LIKE 'pg\_%' AND nspname NOT in ('information_schema'))
|
||||
{% endif %}
|
||||
-- Find function for specific OID
|
||||
{% if tgfoid %}
|
||||
AND p.oid = {{tgfoid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY nspname ASC, proname ASC
|
@@ -0,0 +1,7 @@
|
||||
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
WHERE tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1 @@
|
||||
SELECT 1 WHERE 1 = 2;
|
@@ -0,0 +1,50 @@
|
||||
{% if data.name and o_data.name != data.name %}
|
||||
ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% endif %}
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined) and o_data.lanname == 'edbspl' and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires)) %}
|
||||
{% set or_flag = False %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% if data.fires is defined %}{{data.fires}} {% else %}{{o_data.fires}} {% endif %}{% if data.evnt_insert is not defined %}{% if o_data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% endif %}{% if data.evnt_delete is not defined %}{% if o_data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_truncate is not defined %}{% if o_data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}{% else %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if o_data.tgdeferrable %}
|
||||
DEFERRABLE{% if o_data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
{% endif %}{% if data.is_row_trigger is not defined %}
|
||||
FOR EACH{% if o_data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% else %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% endif %}
|
||||
{% if o_data.whenclause %}
|
||||
WHEN {{ o_data.whenclause }}
|
||||
{% endif %}
|
||||
|
||||
{% if (data.prosrc is not defined) %}
|
||||
{{ o_data.prosrc }};
|
||||
{% else %}
|
||||
{{ data.prosrc }};
|
||||
{% endif %}
|
||||
|
||||
{% if data.description is not defined and o_data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS {{o_data.description|qtLiteral}};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if data.description is defined and o_data.description != data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
||||
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
|
||||
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
|
||||
{% endif %}
|
@@ -0,0 +1,36 @@
|
||||
{### Set a flag which allows us to put OR between events ###}
|
||||
{% set or_flag = False %}
|
||||
{% if data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL' %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% else %}
|
||||
CREATE{% if data.is_constraint_trigger %} CONSTRAINT{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% endif %}
|
||||
{{data.fires}} {% if data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if data.columns|length > 0 %}OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.tgdeferrable %}
|
||||
DEFERRABLE{% if data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
{% endif %}
|
||||
{% if data.tgoldtable or data.tgnewtable %}
|
||||
REFERENCING{% if data.tgnewtable %} NEW TABLE AS {{ conn|qtIdent(data.tgnewtable) }}{% endif %}{% if data.tgoldtable %} OLD TABLE AS {{ conn|qtIdent(data.tgoldtable) }}{% endif %}
|
||||
|
||||
{% endif %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %}
|
||||
{% if data.whenclause %}
|
||||
|
||||
WHEN {% if not data.oid %}({% endif %}{{ data.whenclause }}{% if not data.oid %}){% endif %}{% endif %}
|
||||
|
||||
{% if data.prosrc is defined and
|
||||
(data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL') %}{{ data.prosrc }}{% else %}EXECUTE PROCEDURE {{ data.tfunction }}{% if data.tgargs %}({{ data.tgargs }}){% else %}(){% endif%}{% endif%};
|
||||
|
||||
{% if data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
@@ -0,0 +1,25 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause,
|
||||
-- We need to convert tgargs column bytea datatype to array datatype
|
||||
(string_to_array(encode(tgargs, 'escape'), E'\\000')::text[])[1:tgnargs] AS custom_tgargs,
|
||||
{% if datlastsysoid %}
|
||||
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
|
||||
{% endif %}
|
||||
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger,
|
||||
(CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger,
|
||||
tgoldtable,
|
||||
tgnewtable
|
||||
FROM pg_trigger t
|
||||
JOIN pg_class cl ON cl.oid=tgrelid
|
||||
JOIN pg_namespace na ON na.oid=relnamespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
|
||||
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,10 @@
|
||||
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgpackageoid = 0
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,26 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause,
|
||||
-- We need to convert tgargs column bytea datatype to array datatype
|
||||
(string_to_array(encode(tgargs, 'escape'), E'\\000')::text[])[1:tgnargs] AS custom_tgargs,
|
||||
{% if datlastsysoid %}
|
||||
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
|
||||
{% endif %}
|
||||
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger,
|
||||
(CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger,
|
||||
tgoldtable,
|
||||
tgnewtable
|
||||
FROM pg_trigger t
|
||||
JOIN pg_class cl ON cl.oid=tgrelid
|
||||
JOIN pg_namespace na ON na.oid=relnamespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
|
||||
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgpackageoid = 0
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,5 @@
|
||||
SELECT t.oid
|
||||
FROM pg_trigger t
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgname = {{data.name|qtLiteral}};
|
@@ -0,0 +1,9 @@
|
||||
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,23 @@
|
||||
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
|
||||
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
|
||||
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
|
||||
substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause,
|
||||
-- We need to convert tgargs column bytea datatype to array datatype
|
||||
(string_to_array(encode(tgargs, 'escape'), E'\\000')::text[])[1:tgnargs] AS custom_tgargs,
|
||||
{% if datlastsysoid %}
|
||||
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
|
||||
{% endif %}
|
||||
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger,
|
||||
(CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
JOIN pg_class cl ON cl.oid=tgrelid
|
||||
JOIN pg_namespace na ON na.oid=relnamespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
|
||||
LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1,9 @@
|
||||
{## Alter index to use cluster type ##}
|
||||
{% if data.indisclustered %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
CLUSTER ON {{conn|qtIdent(data.name)}};
|
||||
{% endif %}
|
||||
{## Changes description ##}
|
||||
{% if data.description %}
|
||||
COMMENT ON INDEX {{conn|qtIdent(data.name)}}
|
||||
IS {{data.description|qtLiteral}};{% endif %}
|
@@ -0,0 +1,9 @@
|
||||
{#=============Checks if it is materialized view========#}
|
||||
{% if vid %}
|
||||
SELECT
|
||||
CASE WHEN c.relkind = 'm' THEN False ELSE True END As m_view
|
||||
FROM
|
||||
pg_class c
|
||||
WHERE
|
||||
c.oid = {{ vid }}::oid
|
||||
{% endif %}
|
@@ -0,0 +1,32 @@
|
||||
{### Set a flag which allows us to put OR between events ###}
|
||||
{% set or_flag = False %}
|
||||
{% if data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL' %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% else %}
|
||||
CREATE{% if data.is_constraint_trigger %} CONSTRAINT{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% endif %}
|
||||
{{data.fires}} {% if data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if data.columns|length > 0 %}OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.tgdeferrable %}
|
||||
DEFERRABLE{% if data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
{% endif %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %}
|
||||
{% if data.whenclause %}
|
||||
|
||||
WHEN ({{ data.whenclause }}){% endif %}
|
||||
|
||||
{% if data.prosrc is defined and
|
||||
(data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL') %}{{ data.prosrc }}{% else %}EXECUTE PROCEDURE {{ data.tfunction }}{% if data.tgargs %}({{ data.tgargs }}){% else %}(){% endif%}{% endif%};
|
||||
|
||||
{% if data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
@@ -0,0 +1 @@
|
||||
DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};
|
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
|
@@ -0,0 +1,6 @@
|
||||
SELECT att.attname as name
|
||||
FROM pg_attribute att
|
||||
WHERE att.attrelid = {{tid}}::oid
|
||||
AND att.attnum IN ({{ clist }})
|
||||
AND att.attisdropped IS FALSE
|
||||
ORDER BY att.attnum
|
@@ -0,0 +1,4 @@
|
||||
SELECT t.oid
|
||||
FROM pg_trigger t
|
||||
WHERE tgrelid = {{tid}}::OID
|
||||
AND tgname = {{data.name|qtLiteral}};
|
@@ -0,0 +1,5 @@
|
||||
SELECT nsp.nspname AS schema ,rel.relname AS table
|
||||
FROM pg_class rel
|
||||
JOIN pg_namespace nsp
|
||||
ON rel.relnamespace = nsp.oid::oid
|
||||
WHERE rel.oid = {{tid}}::oid
|
@@ -0,0 +1,15 @@
|
||||
SELECT quote_ident(nspname) || '.' || quote_ident(proname) AS tfunctions
|
||||
FROM pg_proc p, pg_namespace n, pg_language l
|
||||
WHERE p.pronamespace = n.oid
|
||||
AND p.prolang = l.oid
|
||||
-- PGOID_TYPE_TRIGGER = 2279
|
||||
AND l.lanname != 'edbspl' AND prorettype = 2279
|
||||
-- If Show SystemObjects is not true
|
||||
{% if not show_system_objects %}
|
||||
AND (nspname NOT LIKE 'pg\_%' AND nspname NOT in ('information_schema'))
|
||||
{% endif %}
|
||||
-- Find function for specific OID
|
||||
{% if tgfoid %}
|
||||
AND p.oid = {{tgfoid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY nspname ASC, proname ASC
|
@@ -0,0 +1,7 @@
|
||||
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
|
||||
FROM pg_trigger t
|
||||
WHERE tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY tgname;
|
@@ -0,0 +1 @@
|
||||
SELECT 1 WHERE 1 = 2;
|
@@ -0,0 +1,50 @@
|
||||
{% if data.name and o_data.name != data.name %}
|
||||
ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% endif %}
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined) and o_data.lanname == 'edbspl' and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires)) %}
|
||||
{% set or_flag = False %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% if data.fires is defined %}{{data.fires}} {% else %}{{o_data.fires}} {% endif %}{% if data.evnt_insert is not defined %}{% if o_data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% endif %}{% if data.evnt_delete is not defined %}{% if o_data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_truncate is not defined %}{% if o_data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_truncate %}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}{% else %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if o_data.tgdeferrable %}
|
||||
DEFERRABLE{% if o_data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
{% endif %}{% if data.is_row_trigger is not defined %}
|
||||
FOR EACH{% if o_data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% else %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% endif %}
|
||||
{% if o_data.whenclause %}
|
||||
WHEN {{ o_data.whenclause }}
|
||||
{% endif %}
|
||||
|
||||
{% if (data.prosrc is not defined) %}
|
||||
{{ o_data.prosrc }};
|
||||
{% else %}
|
||||
{{ data.prosrc }};
|
||||
{% endif %}
|
||||
|
||||
{% if data.description is not defined and o_data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS {{o_data.description|qtLiteral}};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if data.description is defined and o_data.description != data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS {{data.description|qtLiteral}};
|
||||
{% endif %}
|
||||
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
|
||||
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
|
||||
{% endif %}
|
@@ -37,6 +37,10 @@ class TestTriggerGetOidSql(SQLTemplateTestBase):
|
||||
def generate_sql(self, version):
|
||||
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
|
||||
"triggers", "sql")
|
||||
if 'type' in self.server:
|
||||
file_path = os.path.join(os.path.dirname(__file__), "..",
|
||||
"templates",
|
||||
"triggers", "sql", self.server['type'])
|
||||
template_file = self.get_template_file(version, file_path,
|
||||
"get_oid.sql")
|
||||
jinja2.filters.FILTERS['qtLiteral'] = lambda value: "NULL"
|
||||
|
@@ -32,6 +32,10 @@ class TestTriggerNodesSql(SQLTemplateTestBase):
|
||||
def generate_sql(self, version):
|
||||
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
|
||||
"triggers", "sql")
|
||||
if 'type' in self.server:
|
||||
file_path = os.path.join(os.path.dirname(__file__), "..",
|
||||
"templates",
|
||||
"triggers", "sql", self.server['type'])
|
||||
template_file = self.get_template_file(version, file_path,
|
||||
"nodes.sql")
|
||||
template = file_as_template(template_file)
|
||||
|
@@ -69,4 +69,4 @@ class TestUtils(BaseTestGenerator):
|
||||
'indexes/sql/#gpdb#10#')
|
||||
self.assertEqual(
|
||||
subject.trigger_template_path,
|
||||
'triggers/sql/#gpdb#10#')
|
||||
'triggers/sql/gpdb/#10#')
|
||||
|
@@ -78,7 +78,8 @@ class TriggerModule(CollectionNodeModule):
|
||||
if 'vid' not in kwargs:
|
||||
return True
|
||||
|
||||
template_path = 'triggers/sql/#{0}#'.format(manager.version)
|
||||
template_path = 'triggers/sql/{0}/#{1}#'.format(
|
||||
manager.server_type, manager.version)
|
||||
SQL = render_template("/".join(
|
||||
[template_path, 'backend_support.sql']), vid=kwargs['vid']
|
||||
)
|
||||
@@ -272,8 +273,8 @@ class TriggerView(PGChildNodeView):
|
||||
kwargs['did'] in self.manager.db_info else 0
|
||||
|
||||
# we will set template path for sql scripts
|
||||
self.template_path = 'triggers/sql/#{0}#'.format(
|
||||
self.manager.version)
|
||||
self.template_path = 'triggers/sql/{0}/#{1}#'.format(
|
||||
self.manager.server_type, self.manager.version)
|
||||
# Store server type
|
||||
self.server_type = self.manager.server_type
|
||||
# We need parent's name eg table name and schema name
|
||||
|
@@ -24,15 +24,15 @@ from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as triggers_utils
|
||||
|
||||
|
||||
class TriggersDeleteTestCase(BaseTestGenerator):
|
||||
class TriggersDeleteMultipleTestCase(BaseTestGenerator):
|
||||
"""This class will delete trigger under table node."""
|
||||
skip_on_database = ['gpdb']
|
||||
scenarios = [
|
||||
('Delete trigger Node URL', dict(url='/browser/trigger/obj/'))
|
||||
('Delete multiple triggers', dict(url='/browser/trigger/obj/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(TriggersDeleteTestCase, self).setUp()
|
||||
super(TriggersDeleteMultipleTestCase, self).setUp()
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
schema_info = parent_node_dict["schema"][-1]
|
||||
self.server_id = schema_info["server_id"]
|
||||
|
@@ -57,7 +57,7 @@ class TriggersUpdateTestCase(BaseTestGenerator):
|
||||
self.function_info = \
|
||||
trigger_funcs_utils.create_trigger_function_with_trigger(
|
||||
self.server, self.db_name, self.schema_name, self.func_name)
|
||||
self.trigger_name = "test_trigger_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.trigger_name = "test_trigger_update_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.trigger_id = triggers_utils.create_trigger(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
@@ -71,7 +71,7 @@ class TriggersUpdateTestCase(BaseTestGenerator):
|
||||
self.db_name,
|
||||
self.trigger_name)
|
||||
if not trigger_response:
|
||||
raise Exception("Could not find the trigger to delete.")
|
||||
raise Exception("Could not find the trigger to update.")
|
||||
data = {"id": self.trigger_id,
|
||||
"description": "This is test comment."
|
||||
}
|
||||
|
@@ -139,8 +139,12 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
'indexes/sql', server_type, ver)
|
||||
|
||||
# Template for trigger node
|
||||
self.trigger_template_path = compile_template_path(
|
||||
'triggers/sql', server_type, ver)
|
||||
self.trigger_template_path = \
|
||||
'triggers/sql/{0}/#{1}#'.format(server_type, ver)
|
||||
|
||||
# Template for compound trigger node
|
||||
self.compound_trigger_template_path = \
|
||||
'compound_triggers/sql/{0}/#{1}#'.format(server_type, ver)
|
||||
|
||||
# Template for rules node
|
||||
self.rules_template_path = 'rules/sql'
|
||||
@@ -1014,8 +1018,6 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
trigger_sql = ''
|
||||
|
||||
SQL = render_template("/".join([self.trigger_template_path,
|
||||
'properties.sql']),
|
||||
tid=tid, trid=row['oid'],
|
||||
@@ -1084,9 +1086,90 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
trigger_sql = re.sub('\n{2,}', '\n\n', trigger_sql)
|
||||
main_sql.append(trigger_sql)
|
||||
|
||||
"""
|
||||
#################################################
|
||||
# 4) Reverse engineered sql for COMPOUND TRIGGERS
|
||||
#################################################
|
||||
"""
|
||||
|
||||
if self.manager.server_type == 'ppas' \
|
||||
and self.manager.version >= 120000:
|
||||
SQL = render_template("/".join(
|
||||
[self.compound_trigger_template_path, 'nodes.sql']), tid=tid)
|
||||
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
SQL = render_template("/".join(
|
||||
[self.compound_trigger_template_path, 'properties.sql']),
|
||||
tid=tid, trid=row['oid'],
|
||||
datlastsysoid=self.datlastsysoid)
|
||||
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
if len(res['rows']) == 0:
|
||||
continue
|
||||
data = dict(res['rows'][0])
|
||||
# Adding parent into data dict, will be using it while
|
||||
# creating sql
|
||||
data['schema'] = schema
|
||||
data['table'] = table
|
||||
|
||||
if len(data['tgattr']) >= 1:
|
||||
columns = ', '.join(data['tgattr'].split(' '))
|
||||
|
||||
SQL = render_template("/".join(
|
||||
[self.compound_trigger_template_path,
|
||||
'get_columns.sql']), tid=tid, clist=columns)
|
||||
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
# 'tgattr' contains list of columns from table
|
||||
# used in trigger
|
||||
columns = []
|
||||
|
||||
for col_row in rset['rows']:
|
||||
columns.append(col_row['name'])
|
||||
|
||||
data['columns'] = columns
|
||||
|
||||
data = trigger_definition(data)
|
||||
sql_header = \
|
||||
u"\n-- Compound Trigger: {0}\n\n-- ".format(data['name'])
|
||||
|
||||
sql_header += render_template("/".join(
|
||||
[self.compound_trigger_template_path, 'delete.sql']),
|
||||
data=data, conn=self.conn)
|
||||
|
||||
# If the request for new object which do not have did
|
||||
compound_trigger_sql = render_template("/".join(
|
||||
[self.compound_trigger_template_path, 'create.sql']),
|
||||
data=data, conn=self.conn)
|
||||
|
||||
compound_trigger_sql = \
|
||||
sql_header + '\n\n' + compound_trigger_sql.strip('\n')
|
||||
|
||||
# If trigger is disabled then add sql code for the same
|
||||
if not data['is_enable_trigger']:
|
||||
compound_trigger_sql += '\n\n'
|
||||
compound_trigger_sql += render_template("/".join(
|
||||
[self.compound_trigger_template_path,
|
||||
'enable_disable_trigger.sql']),
|
||||
data=data, conn=self.conn)
|
||||
|
||||
# Add into main sql
|
||||
compound_trigger_sql = \
|
||||
re.sub('\n{2,}', '\n\n', compound_trigger_sql)
|
||||
main_sql.append(compound_trigger_sql)
|
||||
|
||||
"""
|
||||
#####################################
|
||||
# 4) Reverse engineered sql for RULES
|
||||
# 5) Reverse engineered sql for RULES
|
||||
#####################################
|
||||
"""
|
||||
|
||||
@@ -1118,7 +1201,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
|
||||
"""
|
||||
##########################################
|
||||
# 5) Reverse engineered sql for PARTITIONS
|
||||
# 6) Reverse engineered sql for PARTITIONS
|
||||
##########################################
|
||||
"""
|
||||
if is_partitioned:
|
||||
|
@@ -892,7 +892,8 @@ class ViewNode(PGChildNodeView, VacuumSettings):
|
||||
SQL_data = ''
|
||||
SQL = render_template("/".join(
|
||||
[self.trigger_temp_path,
|
||||
'sql/#{0}#/properties.sql'.format(self.manager.version)]),
|
||||
'sql/{0}/#{1}#/properties.sql'.format(
|
||||
self.manager.server_type, self.manager.version)]),
|
||||
tid=vid)
|
||||
|
||||
status, data = self.conn.execute_dict(SQL)
|
||||
@@ -902,7 +903,8 @@ class ViewNode(PGChildNodeView, VacuumSettings):
|
||||
for trigger in data['rows']:
|
||||
SQL = render_template("/".join(
|
||||
[self.trigger_temp_path,
|
||||
'sql/#{0}#/properties.sql'.format(self.manager.version)]),
|
||||
'sql/{0}/#{1}#/properties.sql'.format(
|
||||
self.manager.server_type, self.manager.version)]),
|
||||
tid=vid,
|
||||
trid=trigger['oid']
|
||||
)
|
||||
@@ -932,8 +934,8 @@ class ViewNode(PGChildNodeView, VacuumSettings):
|
||||
# Get trigger function with its schema name
|
||||
SQL = render_template("/".join([
|
||||
self.trigger_temp_path,
|
||||
'sql/#{0}#/get_triggerfunctions.sql'.format(
|
||||
self.manager.version)]),
|
||||
'sql/{0}/#{1}#/get_triggerfunctions.sql'.format(
|
||||
self.manager.server_type, self.manager.version)]),
|
||||
tgfoid=res_rows['tgfoid'],
|
||||
show_system_objects=self.blueprint.show_system_objects)
|
||||
|
||||
@@ -956,7 +958,8 @@ class ViewNode(PGChildNodeView, VacuumSettings):
|
||||
|
||||
SQL = render_template("/".join(
|
||||
[self.trigger_temp_path,
|
||||
'sql/#{0}#/create.sql'.format(self.manager.version)]),
|
||||
'sql/{0}/#{1}#/create.sql'.format(
|
||||
self.manager.server_type, self.manager.version)]),
|
||||
data=res_rows, display_comments=True)
|
||||
SQL_data += '\n'
|
||||
SQL_data += SQL
|
||||
|
@@ -78,12 +78,7 @@ define([
|
||||
data: this.data,
|
||||
}).addClass('dropdown-item');
|
||||
|
||||
if(this.context !== undefined) {
|
||||
this.is_disabled = this.context.disabled;
|
||||
} else {
|
||||
this.is_disabled = this.disabled(node, item);
|
||||
}
|
||||
|
||||
this.is_disabled = this.disabled(node, item);
|
||||
if (this.icon) {
|
||||
url.append($('<i></i>', {
|
||||
'class': this.icon,
|
||||
|
@@ -241,7 +241,8 @@ module.exports = {
|
||||
',pgadmin.node.view' +
|
||||
',pgadmin.node.mview' +
|
||||
',pgadmin.node.table' +
|
||||
',pgadmin.node.partition',
|
||||
',pgadmin.node.partition' +
|
||||
',pgadmin.node.compound_trigger',
|
||||
},
|
||||
}, {
|
||||
test: require.resolve('./node_modules/acitree/js/jquery.aciTree.min'),
|
||||
|
@@ -220,6 +220,7 @@ var webpackShimConfig = {
|
||||
'pgadmin.node.check_constraint': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/js/check_constraint'),
|
||||
'pgadmin.node.collation': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/collations/static/js/collation'),
|
||||
'pgadmin.node.column': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/static/js/column'),
|
||||
'pgadmin.node.compound_trigger': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/static/js/compound_trigger'),
|
||||
'pgadmin.node.constraints': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/js/constraints'),
|
||||
'pgadmin.node.database': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/static/js/database'),
|
||||
'pgadmin.node.domain': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/domains/static/js/domain'),
|
||||
|