Set break point option should present in pgAdmin4 for trigger. Fixes #1226

pull/3/head
Neel Patel 2016-08-29 13:43:43 +05:30 committed by Akshay Joshi
parent 2d75eac117
commit f5249f2e18
3 changed files with 76 additions and 8 deletions

View File

@ -111,10 +111,11 @@ def update_session_function_transaction(trans_id, data):
@blueprint.route('/init/<node_type>/<int:sid>/<int:did>/<int:scid>/<int:fid>', methods=['GET'])
@blueprint.route('/init/<node_type>/<int:sid>/<int:did>/<int:scid>/<int:fid>/<int:trid>', methods=['GET'])
@login_required
def init_function(node_type, sid, did, scid, fid):
def init_function(node_type, sid, did, scid, fid, trid=None):
"""
init_function(node_type, sid, did, scid, fid)
init_function(node_type, sid, did, scid, fid, trid)
This method is responsible to initialize the function required for debugging.
This method is also responsible for storing the all functions data to session variable.
@ -132,6 +133,8 @@ def init_function(node_type, sid, did, scid, fid):
- Schema Id
fid
- Function Id
trid
- Trigger Function Id
"""
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
conn = manager.connection(did=did)
@ -149,6 +152,18 @@ def init_function(node_type, sid, did, scid, fid):
# Set the template path required to read the sql files
template_path = 'debugger/sql'
if node_type == 'trigger':
# Find trigger function id from trigger id
sql = render_template("/".join([template_path, 'get_trigger_function_info.sql']), table_id=fid, trigger_id=trid)
status, tr_set = conn.execute_dict(sql)
if not status:
current_app.logger.debug("Error retrieving trigger function information from database")
return internal_server_error(errormsg=tr_set)
fid = tr_set['rows'][0]['tgfoid']
sql = ''
sql = render_template("/".join([template_path, 'get_function_debug_info.sql']), is_ppas_database=ppas_server,
hasFeatureFunctionDefaults=True, fid=fid)
status, r_set = conn.execute_dict(sql)
@ -166,9 +181,6 @@ def init_function(node_type, sid, did, scid, fid):
if ":" in r_set['rows'][0]['name']:
ret_status = False
msg = gettext("Functions with a colon in the name cannot be debugged.")
elif node_type != 'trigger' and r_set['rows'][0]['rettype'] == 'trigger':
ret_status = False
msg = gettext("Functions with return type of 'trigger' cannot be debugged.")
elif ppas_server and r_set['rows'][0]['prosrc'].lstrip().startswith('$__EDBwrapped__$'):
ret_status = False
msg = gettext("EDB Advanced Server wrapped functions cannot be debugged.")
@ -304,10 +316,12 @@ def direct_new(trans_id):
@blueprint.route('/initialize_target/<debug_type>/<int:sid>/<int:did>/<int:scid>/<int:func_id>',
methods=['GET', 'POST'])
@blueprint.route('/initialize_target/<debug_type>/<int:sid>/<int:did>/<int:scid>/<int:func_id>/<int:tri_id>',
methods=['GET', 'POST'])
@login_required
def initialize_target(debug_type, sid, did, scid, func_id):
def initialize_target(debug_type, sid, did, scid, func_id, tri_id=None):
"""
initialize_target(debug_type, sid, did, scid, func_id)
initialize_target(debug_type, sid, did, scid, func_id, tri_id)
This method is responsible for creating an asynchronous connection.
It will also create a unique transaction id and store the information
@ -324,6 +338,8 @@ def initialize_target(debug_type, sid, did, scid, func_id):
- Schema Id
func_id
- Function Id
tri_id
- Trigger Function Id
"""
# Create asynchronous connection using random connection id.
@ -339,6 +355,20 @@ def initialize_target(debug_type, sid, did, scid, func_id):
if not status:
return internal_server_error(errormsg=str(msg))
# Set the template path required to read the sql files
template_path = 'debugger/sql'
if tri_id is not None:
# Find trigger function id from trigger id
sql = render_template("/".join([template_path, 'get_trigger_function_info.sql']), table_id=func_id, trigger_id=tri_id)
status, tr_set = conn.execute_dict(sql)
if not status:
current_app.logger.debug("Error retrieving trigger function information from database")
return internal_server_error(errormsg=tr_set)
func_id = tr_set['rows'][0]['tgfoid']
# Create a unique id for the transaction
trans_id = str(random.randint(1, 9999999))

View File

@ -46,6 +46,18 @@ define(
category: 'Debugging', priority: 10, label: '{{ _('Set breakpoint') }}',
data: {object: 'procedure'}, icon: 'fa fa-arrow-circle-right',
enable: 'can_debug'
}, {
name: 'trigger_function_indirect_debugger', node: 'trigger_function', module: this,
applies: ['object', 'context'], callback: 'check_func_debuggable',
priority: 10, label: '{{ _('Set breakpoint') }}', category: 'Debugging',
icon: 'fa fa-arrow-circle-right', data: {object:'trigger_function'},
enable: 'can_debug'
}, {
name: 'trigger_indirect_debugger', node: 'trigger', module: this,
applies: ['object', 'context'], callback: 'check_func_debuggable',
priority: 10, label: '{{ _('Set breakpoint') }}', category: 'Debugging',
icon: 'fa fa-arrow-circle-right', data: {object:'trigger'},
enable: 'can_debug'
}]);
// Create and load the new frame required for debugger panel
@ -89,6 +101,11 @@ define(
if (!(treeInfo.server.user.is_superuser || treeInfo.function.funcowner == treeInfo.server.user.name))
return false;
// For trigger node, language will be undefined - we should allow indirect debugging for trigger node
if (d_.language == undefined && d_._type == 'trigger') {
return true;
}
if (d_.language != 'plpgsql' && d_.language != 'edbspl') {
return false;
}
@ -178,10 +195,19 @@ define(
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "indirect/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.function._id;
}
else {
else if (d._type == "procedure") {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "indirect/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.procedure._id;
}
else if (d._type == "trigger_function") {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "indirect/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.trigger_function._id;
}
else if (d._type == "trigger") {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "indirect/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.table._id +
"/" + treeInfo.trigger._id;
}
$.ajax({
url: baseUrl,

View File

@ -0,0 +1,12 @@
{### To fetch trigger function information ###}
SELECT t.oid, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, nspname, des.description, l.lanname, p.prosrc,
COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'), substring(pg_get_triggerdef(t.oid), 'WHEN (.*) \$trigger')) AS whenclause
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 = {{table_id}}::oid AND t.oid = {{trigger_id}}::oid
ORDER BY tgname