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.
This commit is contained in:
Akshay Joshi
2019-08-08 16:48:46 +05:30
parent 8331f62e1c
commit 350ffcce7c
96 changed files with 3052 additions and 35 deletions

View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@@ -17,6 +17,7 @@ node, and select *Create Cast...*
check_dialog
column_dialog
compound_trigger_dialog
exclusion_constraint_dialog
foreign_key_dialog
index_dialog

View File

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

View File

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

View File

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

View File

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

View File

@@ -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'];
});

View File

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

View File

@@ -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 []

View File

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

View File

@@ -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_$%{}[]()&*^!@""'`\/#";

View File

@@ -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_$%{}[]()&*^!@""'`\/#";

View File

@@ -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_$%{}[]()&*^!@""'`\/#";

View File

@@ -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_$%{}[]()&*^!@\"'`\\/#"
}
}
]
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 %}

View File

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

View File

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

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -0,0 +1 @@
DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
SELECT t.oid
FROM pg_trigger t
WHERE tgrelid = {{tid}}::OID
AND tgname = {{data.name|qtLiteral}};

View File

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

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -0,0 +1,5 @@
SELECT t.oid
FROM pg_trigger t
WHERE NOT tgisinternal
AND tgrelid = {{tid}}::OID
AND tgname = {{data.name|qtLiteral}};

View File

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

View File

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

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -0,0 +1 @@
DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
SELECT t.oid
FROM pg_trigger t
WHERE tgrelid = {{tid}}::OID
AND tgname = {{data.name|qtLiteral}};

View File

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

View File

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

View File

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

View File

@@ -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 %}

View File

@@ -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 %}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
SELECT t.oid
FROM pg_trigger t
WHERE NOT tgisinternal
AND tgrelid = {{tid}}::OID
AND tgname = {{data.name|qtLiteral}};

View File

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

View File

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

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -0,0 +1 @@
DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
SELECT t.oid
FROM pg_trigger t
WHERE tgrelid = {{tid}}::OID
AND tgname = {{data.name|qtLiteral}};

View File

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

View File

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

View File

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

View File

@@ -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 %}

View File

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

View File

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

View 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#')

View File

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

View File

@@ -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"]

View File

@@ -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."
}

View File

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

View File

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

View File

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

View File

@@ -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'),

View File

@@ -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'),