Support Enable Always and Enable Replica on triggers. Fixes #4006

This commit is contained in:
Aditya Toshniwal 2019-11-01 11:49:17 +00:00 committed by Dave Page
parent ab5d954337
commit 131a944e24
39 changed files with 131 additions and 86 deletions

View File

@ -24,6 +24,13 @@ Use the fields in the *General* tab to identify the compound trigger:
The name will be displayed in the *pgAdmin* tree control. The name will be displayed in the *pgAdmin* tree control.
* Store notes about the compound trigger in the *Comment* field. * Store notes about the compound trigger in the *Comment* field.
.. image:: images/compound_trigger_general_enabled.png
:alt: Trigger enabled in dialog tab
:align: center
* *Trigger enabled* field is available in compound trigger dialog once the trigger is created.
You can select one of the four options available.
Click the *Events* tab to continue. Click the *Events* tab to continue.
.. image:: images/compound_trigger_events.png .. image:: images/compound_trigger_events.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -11,6 +11,7 @@ New features
| `Issue #1974 <https://redmine.postgresql.org/issues/1974>`_ - Added encrypted password in reverse engineered SQL for roles. | `Issue #1974 <https://redmine.postgresql.org/issues/1974>`_ - Added encrypted password in reverse engineered SQL for roles.
| `Issue #4351 <https://redmine.postgresql.org/issues/4351>`_ - Add an option to request confirmation before cancelling changes on a Properties dialog. | `Issue #4351 <https://redmine.postgresql.org/issues/4351>`_ - Add an option to request confirmation before cancelling changes on a Properties dialog.
| `Issue #4006 <https://redmine.postgresql.org/issues/4006>`_ - Support Enable Always and Enable Replica on triggers.
Housekeeping Housekeeping
************ ************

View File

@ -48,6 +48,13 @@ Use the fields in the *Definition* tab to define the trigger:
arguments to the function when the trigger is executed. The arguments are arguments to the function when the trigger is executed. The arguments are
literal string constants. literal string constants.
.. image:: images/trigger_definition_enabled.png
:alt: Trigger enabled in dialog tab
:align: center
* *Trigger enabled* field is available in trigger dialog once the trigger is created.
You can select one of the four options available.
Click the *Events* tab to continue. Click the *Events* tab to continue.
.. image:: images/trigger_events.png .. image:: images/trigger_events.png

View File

@ -1228,7 +1228,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
request.data, encoding='utf-8' request.data, encoding='utf-8'
) )
# Convert str 'true' to boolean type # Convert str 'true' to boolean type
is_enable = json.loads(data['enable']) is_enable_trigger = data['is_enable_trigger']
try: try:
SQL = render_template( SQL = render_template(
@ -1245,7 +1245,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
"/".join([ "/".join([
self.table_template_path, 'enable_disable_trigger.sql' self.table_template_path, 'enable_disable_trigger.sql'
]), ]),
data=data, is_enable_trigger=is_enable data=data, is_enable_trigger=is_enable_trigger
) )
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
@ -1253,8 +1253,9 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Trigger(s) have been enabled") if is_enable info=gettext("Trigger(s) have been disabled")
else gettext("Trigger(s) have been disabled"), if is_enable_trigger == 'D'
else gettext("Trigger(s) have been enabled"),
data={ data={
'id': tid, 'id': tid,
'scid': scid 'scid': scid

View File

@ -372,9 +372,9 @@ class CompoundTriggerView(PGChildNodeView):
rset['rows'][0]['oid'], rset['rows'][0]['oid'],
tid, tid,
rset['rows'][0]['name'], rset['rows'][0]['name'],
icon="icon-compound_trigger" if icon="icon-compound_trigger-bad" if
rset['rows'][0]['is_enable_trigger'] else rset['rows'][0]['is_enable_trigger'] == 'D' else
"icon-compound_trigger-bad" "icon-compound_trigger"
) )
return make_json_response( return make_json_response(
@ -412,8 +412,9 @@ class CompoundTriggerView(PGChildNodeView):
row['oid'], row['oid'],
tid, tid,
row['name'], row['name'],
icon="icon-compound_trigger" if row['is_enable_trigger'] icon="icon-compound_trigger-bad"
else "icon-compound_trigger-bad" if row['is_enable_trigger'] == 'D'
else "icon-compound_trigger"
)) ))
return make_json_response( return make_json_response(
@ -736,9 +737,9 @@ class CompoundTriggerView(PGChildNodeView):
new_trid, new_trid,
tid, tid,
name, name,
icon="icon-%s" % self.node_type if icon="icon-%s-bad" % self.node_type if
data['is_enable_trigger'] else data['is_enable_trigger'] == 'D' else
"icon-%s-bad" % self.node_type "icon-%s" % self.node_type
) )
) )
except Exception as e: except Exception as e:
@ -889,7 +890,7 @@ class CompoundTriggerView(PGChildNodeView):
SQL = sql_header + '\n\n' + SQL.strip('\n') SQL = sql_header + '\n\n' + SQL.strip('\n')
# If compound trigger is disbaled then add sql code for the same # If compound trigger is disbaled then add sql code for the same
if not data['is_enable_trigger']: if data['is_enable_trigger'] != 'O':
SQL += '\n\n' SQL += '\n\n'
SQL += render_template("/".join([self.template_path, SQL += render_template("/".join([self.template_path,
'enable_disable_trigger.sql']), 'enable_disable_trigger.sql']),
@ -917,7 +918,7 @@ class CompoundTriggerView(PGChildNodeView):
) )
# Convert str 'true' to boolean type # Convert str 'true' to boolean type
is_enable_flag = json.loads(data['enable']) is_enable_trigger = data['is_enable_trigger']
try: try:
@ -940,7 +941,7 @@ class CompoundTriggerView(PGChildNodeView):
# current compound trigger which is disabled already so we need to # current compound trigger which is disabled already so we need to
# alter the 'is_enable_trigger' flag so that we can render # alter the 'is_enable_trigger' flag so that we can render
# correct SQL for operation # correct SQL for operation
o_data['is_enable_trigger'] = is_enable_flag o_data['is_enable_trigger'] = is_enable_trigger
# Adding parent into data dict, will be using it while creating sql # Adding parent into data dict, will be using it while creating sql
o_data['schema'] = self.schema o_data['schema'] = self.schema

View File

@ -108,7 +108,7 @@ define('pgadmin.node.compound_trigger', [
$.ajax({ $.ajax({
url: obj.generate_url(i, 'enable' , d, true), url: obj.generate_url(i, 'enable' , d, true),
type:'PUT', type:'PUT',
data: {'enable' : true}, data: {'is_enable_trigger' : 'O'},
dataType: 'json', dataType: 'json',
}) })
.done(function(res) { .done(function(res) {
@ -146,7 +146,7 @@ define('pgadmin.node.compound_trigger', [
$.ajax({ $.ajax({
url: obj.generate_url(i, 'enable' , d, true), url: obj.generate_url(i, 'enable' , d, true),
type:'PUT', type:'PUT',
data: {'enable' : false}, data: {'is_enable_trigger' : 'D'},
dataType: 'json', dataType: 'json',
}) })
.done(function(res) { .done(function(res) {
@ -185,13 +185,20 @@ define('pgadmin.node.compound_trigger', [
type: 'int', disabled: true, mode: ['properties'], type: 'int', disabled: true, mode: ['properties'],
},{ },{
id: 'is_enable_trigger', label: gettext('Trigger enabled?'), id: 'is_enable_trigger', label: gettext('Trigger enabled?'),
type: 'switch', mode: ['edit', 'properties'], mode: ['edit', 'properties'],
disabled: function() { disabled: function() {
if(this.node_info && ('catalog' in this.node_info || 'view' in this.node_info)) { if(this.node_info && ('catalog' in this.node_info || 'view' in this.node_info)) {
return true; return true;
} }
return false; return false;
}, },
options: [
{label: 'Enable', value: 'O'},
{label: 'Enable Replica', value: 'R'},
{label: 'Enable Always', value: 'A'},
{label: 'Disable', value: 'D'},
],
control: 'select2', select2: { allowClear: false, width: '100%' },
},{ },{
type: 'nested', control: 'fieldset', mode: ['create','edit', 'properties'], type: 'nested', control: 'fieldset', mode: ['create','edit', 'properties'],
label: gettext('FOR Events'), group: gettext('Events'), contentClass: 'row', label: gettext('FOR Events'), group: gettext('Events'), contentClass: 'row',

View File

@ -45,12 +45,20 @@ class CompoundTriggersUpdateTestCase(BaseTestGenerator):
})), })),
('Enable compound trigger', ('Enable compound trigger',
dict(url='/browser/compound_trigger/obj/', dict(url='/browser/compound_trigger/obj/',
data={"is_enable_trigger": True}, data={"is_enable_trigger": 'O'},
disable_trigger=True disable_trigger=True
)), )),
('Enable always compound trigger',
dict(url='/browser/compound_trigger/obj/',
data={"is_enable_trigger": 'A'}
)),
('Enable replica compound trigger',
dict(url='/browser/compound_trigger/obj/',
data={"is_enable_trigger": 'R'}
)),
('Disable compound trigger', ('Disable compound trigger',
dict(url='/browser/compound_trigger/obj/', dict(url='/browser/compound_trigger/obj/',
data={"is_enable_trigger": False} data={"is_enable_trigger": 'D'}
)), )),
] ]

View File

@ -10,10 +10,10 @@
import axios from 'axios'; import axios from 'axios';
export function disableTriggers(tree, alertify, generateUrl, args) { export function disableTriggers(tree, alertify, generateUrl, args) {
return setTriggers(tree, alertify, generateUrl, args, {enable: 'false' }); return setTriggers(tree, alertify, generateUrl, args, {is_enable_trigger: 'D' });
} }
export function enableTriggers(tree, alertify, generateUrl, args) { export function enableTriggers(tree, alertify, generateUrl, args) {
return setTriggers(tree, alertify, generateUrl, args, {enable: 'true' }); return setTriggers(tree, alertify, generateUrl, args, {is_enable_trigger: 'O' });
} }
function setTriggers(tree, alertify, generateUrl, args, params) { function setTriggers(tree, alertify, generateUrl, args, params) {

View File

@ -1,2 +1,3 @@
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};

View File

@ -1,4 +1,4 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE NOT tgisinternal WHERE NOT tgisinternal

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.tgtype, t.tgattr, relname, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.tgtype, t.tgattr, relname,
CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, nspname, des.description,
regexp_replace(regexp_replace(pg_get_triggerdef(t.oid), regexp_replace(regexp_replace(pg_get_triggerdef(t.oid),
@ -6,9 +6,8 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.tgtype, t.tgattr, relname,
) AS prosrc, ) AS prosrc,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \nCOMPOUND'), NULL) AS whenclause, COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \nCOMPOUND'), NULL) AS whenclause,
{% if datlastsysoid %} {% if datlastsysoid %}
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger
{% endif %} {% endif %}
(CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
JOIN pg_class cl ON cl.oid=tgrelid JOIN pg_class cl ON cl.oid=tgrelid
JOIN pg_namespace na ON na.oid=relnamespace JOIN pg_namespace na ON na.oid=relnamespace

View File

@ -38,6 +38,7 @@ COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspna
IS {{data.description|qtLiteral}}; IS {{data.description|qtLiteral}};
{% endif %} {% endif %}
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %} {% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }} 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) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};
{% endif %} {% endif %}

View File

@ -1,2 +1,3 @@
{% set enable_map = {'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }} ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }}
{% if is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER ALL; {{ enable_map[is_enable_trigger] }} TRIGGER ALL;

View File

@ -1,6 +1,5 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE NOT tgisinternal WHERE NOT tgisinternal
AND tgrelid = {{tid}}::OID AND tgrelid = {{tid}}::OID
{% if trid %} {% if trid %}

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction, nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), 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,
@ -7,8 +7,7 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THE
{% if datlastsysoid %} {% if datlastsysoid %}
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
{% endif %} {% endif %}
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger, (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 FROM pg_trigger t
JOIN pg_class cl ON cl.oid=tgrelid JOIN pg_class cl ON cl.oid=tgrelid
JOIN pg_namespace na ON na.oid=relnamespace JOIN pg_namespace na ON na.oid=relnamespace

View File

@ -1,2 +1,3 @@
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};

View File

@ -1,4 +1,4 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE tgrelid = {{tid}}::OID WHERE tgrelid = {{tid}}::OID
{% if trid %} {% if trid %}

View File

@ -45,6 +45,7 @@ COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspna
IS {{data.description|qtLiteral}}; IS {{data.description|qtLiteral}};
{% endif %} {% endif %}
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %} {% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }} 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) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};
{% endif %} {% endif %}

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction, nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), 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,
@ -8,7 +8,6 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THE
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
{% endif %} {% endif %}
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger, (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, tgoldtable,
tgnewtable tgnewtable
FROM pg_trigger t FROM pg_trigger t

View File

@ -1,6 +1,5 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE NOT tgisinternal WHERE NOT tgisinternal
AND tgrelid = {{tid}}::OID AND tgrelid = {{tid}}::OID
{% if trid %} {% if trid %}

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction, nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), 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,
@ -7,8 +7,7 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THE
{% if datlastsysoid %} {% if datlastsysoid %}
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
{% endif %} {% endif %}
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger, (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 FROM pg_trigger t
JOIN pg_class cl ON cl.oid=tgrelid JOIN pg_class cl ON cl.oid=tgrelid
JOIN pg_namespace na ON na.oid=relnamespace JOIN pg_namespace na ON na.oid=relnamespace

View File

@ -1,2 +1,3 @@
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};

View File

@ -1,4 +1,4 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE tgrelid = {{tid}}::OID WHERE tgrelid = {{tid}}::OID
{% if trid %} {% if trid %}

View File

@ -45,6 +45,7 @@ COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspna
IS {{data.description|qtLiteral}}; IS {{data.description|qtLiteral}};
{% endif %} {% endif %}
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %} {% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }} 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) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};
{% endif %} {% endif %}

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction, nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), 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,
@ -8,7 +8,6 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THE
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
{% endif %} {% endif %}
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger, (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, tgoldtable,
tgnewtable tgnewtable
FROM pg_trigger t FROM pg_trigger t

View File

@ -1,6 +1,5 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE NOT tgisinternal WHERE NOT tgisinternal
AND tgrelid = {{tid}}::OID AND tgrelid = {{tid}}::OID
AND tgpackageoid = 0 AND tgpackageoid = 0

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction, nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), 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,
@ -8,7 +8,6 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THE
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
{% endif %} {% endif %}
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger, (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, tgoldtable,
tgnewtable tgnewtable
FROM pg_trigger t FROM pg_trigger t

View File

@ -1,6 +1,5 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE NOT tgisinternal WHERE NOT tgisinternal
AND tgrelid = {{tid}}::OID AND tgrelid = {{tid}}::OID
{% if trid %} {% if trid %}

View File

@ -1,4 +1,4 @@
SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, SELECT t.oid,t.tgname AS name, t.xmin, t.tgenabled AS is_enable_trigger, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction, nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), 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,
@ -7,8 +7,7 @@ SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THE
{% if datlastsysoid %} {% if datlastsysoid %}
(CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger, (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
{% endif %} {% endif %}
(CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constraint_trigger, (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 FROM pg_trigger t
JOIN pg_class cl ON cl.oid=tgrelid JOIN pg_class cl ON cl.oid=tgrelid
JOIN pg_namespace na ON na.oid=relnamespace JOIN pg_namespace na ON na.oid=relnamespace

View File

@ -1,2 +1,3 @@
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
{% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};

View File

@ -1,4 +1,4 @@
SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
FROM pg_trigger t FROM pg_trigger t
WHERE tgrelid = {{tid}}::OID WHERE tgrelid = {{tid}}::OID
{% if trid %} {% if trid %}

View File

@ -45,6 +45,7 @@ COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspna
IS {{data.description|qtLiteral}}; IS {{data.description|qtLiteral}};
{% endif %} {% endif %}
{% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %} {% if data.is_enable_trigger is defined and o_data.is_enable_trigger != data.is_enable_trigger %}
{% set enable_map = {'R':'ENABLE REPLICA', 'A':'ENABLE ALWAYS', 'O':'ENABLE', 'D':'DISABLE'} %}
ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }} 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) }}; {{ enable_map[data.is_enable_trigger] }} TRIGGER {{ conn|qtIdent(data.name) }};
{% endif %} {% endif %}

View File

@ -410,8 +410,8 @@ class TriggerView(PGChildNodeView):
rset['rows'][0]['oid'], rset['rows'][0]['oid'],
tid, tid,
rset['rows'][0]['name'], rset['rows'][0]['name'],
icon="icon-trigger" if icon="icon-trigger-bad" if
rset['rows'][0]['is_enable_trigger'] else "icon-trigger-bad" rset['rows'][0]['is_enable_trigger'] == 'D' else "icon-trigger"
) )
return make_json_response( return make_json_response(
@ -449,8 +449,8 @@ class TriggerView(PGChildNodeView):
row['oid'], row['oid'],
tid, tid,
row['name'], row['name'],
icon="icon-trigger" if row['is_enable_trigger'] icon="icon-trigger-bad" if row['is_enable_trigger'] == 'D'
else "icon-trigger-bad" else "icon-trigger"
)) ))
return make_json_response( return make_json_response(
@ -804,9 +804,9 @@ class TriggerView(PGChildNodeView):
new_trid, new_trid,
tid, tid,
name, name,
icon="icon-%s" % self.node_type if icon="icon-%s-bad" % self.node_type if
data['is_enable_trigger'] else data['is_enable_trigger'] == 'D' else
"icon-%s-bad" % self.node_type "icon-%s" % self.node_type
) )
) )
except Exception as e: except Exception as e:
@ -999,7 +999,7 @@ class TriggerView(PGChildNodeView):
SQL = sql_header + '\n\n' + SQL.strip('\n') SQL = sql_header + '\n\n' + SQL.strip('\n')
# If trigger is disbaled then add sql code for the same # If trigger is disbaled then add sql code for the same
if not data['is_enable_trigger']: if data['is_enable_trigger'] != 'O':
SQL += '\n\n' SQL += '\n\n'
SQL += render_template("/".join([self.template_path, SQL += render_template("/".join([self.template_path,
'enable_disable_trigger.sql']), 'enable_disable_trigger.sql']),
@ -1025,8 +1025,7 @@ class TriggerView(PGChildNodeView):
request.data, encoding='utf-8' request.data, encoding='utf-8'
) )
# Convert str 'true' to boolean type is_enable_trigger = data['is_enable_trigger']
is_enable_flag = json.loads(data['enable'])
try: try:
@ -1049,7 +1048,7 @@ class TriggerView(PGChildNodeView):
# current trigger which is disabled already so we need to # current trigger which is disabled already so we need to
# alter the 'is_enable_trigger' flag so that we can render # alter the 'is_enable_trigger' flag so that we can render
# correct SQL for operation # correct SQL for operation
o_data['is_enable_trigger'] = is_enable_flag o_data['is_enable_trigger'] = is_enable_trigger
# Adding parent into data dict, will be using it while creating sql # Adding parent into data dict, will be using it while creating sql
o_data['schema'] = self.schema o_data['schema'] = self.schema

View File

@ -108,7 +108,7 @@ define('pgadmin.node.trigger', [
$.ajax({ $.ajax({
url: obj.generate_url(i, 'enable' , d, true), url: obj.generate_url(i, 'enable' , d, true),
type:'PUT', type:'PUT',
data: {'enable' : true}, data: {'is_enable_trigger' : 'O'},
dataType: 'json', dataType: 'json',
}) })
.done(function(res) { .done(function(res) {
@ -146,7 +146,7 @@ define('pgadmin.node.trigger', [
$.ajax({ $.ajax({
url: obj.generate_url(i, 'enable' , d, true), url: obj.generate_url(i, 'enable' , d, true),
type:'PUT', type:'PUT',
data: {'enable' : false}, data: {'is_enable_trigger' : 'D'},
dataType: 'json', dataType: 'json',
}) })
.done(function(res) { .done(function(res) {
@ -187,13 +187,20 @@ define('pgadmin.node.trigger', [
type: 'int', disabled: true, mode: ['properties'], type: 'int', disabled: true, mode: ['properties'],
},{ },{
id: 'is_enable_trigger', label: gettext('Trigger enabled?'), id: 'is_enable_trigger', label: gettext('Trigger enabled?'),
type: 'switch', mode: ['edit', 'properties'], group: gettext('Definition'), mode: ['edit', 'properties'], group: gettext('Definition'),
disabled: function() { disabled: function() {
if(this.node_info && ('catalog' in this.node_info || 'view' in this.node_info)) { if(this.node_info && ('catalog' in this.node_info || 'view' in this.node_info)) {
return true; return true;
} }
return false; return false;
}, },
options: [
{label: 'Enable', value: 'O'},
{label: 'Enable Replica', value: 'R'},
{label: 'Enable Always', value: 'A'},
{label: 'Disable', value: 'D'},
],
control: 'select2', select2: { allowClear: false, width: '100%' },
},{ },{
id: 'is_row_trigger', label: gettext('Row trigger?'), id: 'is_row_trigger', label: gettext('Row trigger?'),
type: 'switch', group: gettext('Definition'), type: 'switch', group: gettext('Definition'),
@ -352,7 +359,6 @@ define('pgadmin.node.trigger', [
return view_options; return view_options;
} }
}, },
// If create mode then by default open composite type
control: 'select2', select2: { allowClear: false, width: '100%' }, control: 'select2', select2: { allowClear: false, width: '100%' },
disabled: function(m) { disabled: function(m) {
// If contraint trigger is set to True then only enable it // If contraint trigger is set to True then only enable it

View File

@ -28,7 +28,18 @@ class TriggersUpdateTestCase(BaseTestGenerator):
"""This class will update trigger under table node.""" """This class will update trigger under table node."""
skip_on_database = ['gpdb'] skip_on_database = ['gpdb']
scenarios = [ scenarios = [
('Put trigger Node URL', dict(url='/browser/trigger/obj/')) ('Put trigger Node URL', dict(
url='/browser/trigger/obj/',
data={"description": "This is test comment."})),
('Enable Always compound trigger',
dict(url='/browser/trigger/obj/',
data={"is_enable_trigger": 'A'})),
('Enable Replica compound trigger',
dict(url='/browser/trigger/obj/',
data={"is_enable_trigger": 'R'})),
('Disable compound trigger',
dict(url='/browser/trigger/obj/',
data={"is_enable_trigger": 'D'})),
] ]
def setUp(self): def setUp(self):
@ -72,15 +83,14 @@ class TriggersUpdateTestCase(BaseTestGenerator):
self.trigger_name) self.trigger_name)
if not trigger_response: if not trigger_response:
raise Exception("Could not find the trigger to update.") raise Exception("Could not find the trigger to update.")
data = {"id": self.trigger_id,
"description": "This is test comment." self.data.update({"id": self.trigger_id})
}
response = self.tester.put( response = self.tester.put(
"{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP, "{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP,
self.server_id, self.db_id, self.server_id, self.db_id,
self.schema_id, self.table_id, self.schema_id, self.table_id,
self.trigger_id), self.trigger_id),
data=json.dumps(data), data=json.dumps(self.data),
follow_redirects=True follow_redirects=True
) )
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)

View File

@ -1075,7 +1075,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
trigger_sql = sql_header + '\n\n' + trigger_sql.strip('\n') trigger_sql = sql_header + '\n\n' + trigger_sql.strip('\n')
# If trigger is disabled then add sql code for the same # If trigger is disabled then add sql code for the same
if not data['is_enable_trigger']: if data['is_enable_trigger'] != 'O':
trigger_sql += '\n\n' trigger_sql += '\n\n'
trigger_sql += render_template("/".join([ trigger_sql += render_template("/".join([
self.trigger_template_path, self.trigger_template_path,
@ -1155,7 +1155,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
sql_header + '\n\n' + compound_trigger_sql.strip('\n') sql_header + '\n\n' + compound_trigger_sql.strip('\n')
# If trigger is disabled then add sql code for the same # If trigger is disabled then add sql code for the same
if not data['is_enable_trigger']: if data['is_enable_trigger'] != 'O':
compound_trigger_sql += '\n\n' compound_trigger_sql += '\n\n'
compound_trigger_sql += render_template("/".join( compound_trigger_sql += render_template("/".join(
[self.compound_trigger_template_path, [self.compound_trigger_template_path,

View File

@ -106,7 +106,7 @@ describe('#enableTriggers', () => {
it('call backend with the correct parameters', (done) => { it('call backend with the correct parameters', (done) => {
enableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]}); enableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
setTimeout(() => { setTimeout(() => {
expect(networkMockCalledWith.data).toEqual(JSON.stringify({enable: 'true'})); expect(networkMockCalledWith.data).toEqual(JSON.stringify({is_enable_trigger: 'O'}));
done(); done();
}, 0); }, 0);
}); });
@ -234,7 +234,7 @@ describe('#disableTriggers', () => {
it('call backend with the correct parameters', (done) => { it('call backend with the correct parameters', (done) => {
disableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]}); disableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
setTimeout(() => { setTimeout(() => {
expect(networkMockCalledWith.data).toEqual(JSON.stringify({enable: 'false'})); expect(networkMockCalledWith.data).toEqual(JSON.stringify({is_enable_trigger: 'D'}));
done(); done();
}, 0); }, 0);
}); });