Procedural language debugger.

This commit is contained in:
Neel Patel
2016-04-14 21:36:04 +01:00
committed by Dave Page
parent 1b442cff41
commit 12ae40fe62
57 changed files with 4669 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
.navbar-static-top, .navbar-fixed-top, .navbar-fixed-bottom {
background-image: linear-gradient(to bottom, #CCC 0%, #D2D2D2 100%);
}
.btn-default {
background-color: #D2D2D2;
left: 0px;
right: 0px;
padding: 7px;
}
.btn-toolbar {
padding-top: 3px;
padding-bottom: 3px;
}
#container {
position: absolute;
top: 44px;
bottom: 0px;
left: 0px;
right: 0px;
}
.full-container {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom:0px;
}
.full-container-pane {
width: 100%;
height: 100%;
}
.top-container {
min-height: 300px;
height: 100%;
}
.pg-debugger-panel {
height: 100%;
width: 100%;
position: absolute;
top: 0; bottom: 0; right: 0; left: 0;
}
.wcLoadingIcon {
position: absolute;
font-size: 100px;
left: calc(50% - 100px);
top: calc(50% - 100px);
height: 95px;
}
.wcLoadingLabel {
position: absolute;
width: 103%;
font-size: 30px;
top: calc(50% + 0px);
text-align: center;
}
.top-container .breakpoints {
width: 0.9em;
}
.top-container .CodeMirror-activeline-background {
background: #50B0F0;
}

View File

@@ -0,0 +1,63 @@
{% extends "base.html" %}
{% block title %}{{ _('Debugger - ') + function_name }}{% endblock %}
{% block init_script %}
try {
require(
['pgadmin', 'pgadmin.tools.debugger.direct'],
function(pgAdmin, pgDirectDebug) {
pgDirectDebug.init({{ uniqueId }}, {{ debug_type }});
},
function() {
/* TODO:: Show proper error dialog */
console.log(arguments);
});
} catch (err) {
/* Show proper error dialog */
console.log(err);
}
{% endblock %}
{% block body %}
<nav class="navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<div id="btn-toolbar" class="btn-toolbar" role="toolbar" aria-label="">
<div class="btn-group" role="group" aria-label="">
<button type="button" class="btn btn-default btn-step-into" title="{{ _('Step into') }}">
<i class="fa fa-indent"></i>
</button>
<button type="button" class="btn btn-default btn-step-over" title="{{ _('Step over') }}">
<i class="fa fa-outdent"></i>
</button>
<button type="button" class="btn btn-default btn-continue" title="{{ _('Continue/Start') }}">
<i class="fa fa-play-circle"></i>
</button>
</div>
<div class="btn-group" role="group" aria-label="">
<button type="button" class="btn btn-default btn-toggle-breakpoint" title="{{ _('Toggle breakpoint') }}">
<i class="fa fa-circle"></i>
</button>
<button type="button" class="btn btn-default btn-clear-breakpoint" title="{{ _('Clear all breakpoints') }}">
<i class="fa fa-ban"></i>
</button>
</div>
<div class="btn-group" role="group" aria-label="">
<button type="button" class="btn btn-default btn-stop" title="{{ _('Stop') }}">
<i class="fa fa-stop-circle"></i>
</button>
</div>
</div>
</ul>
</div>
</div>
</nav>
<div id="container"></div>
{% endblock %}
{% block css_link %}
{% for stylesheet in stylesheets %}
<link type="text/css" rel="stylesheet" href="{{ stylesheet }}"/>
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,329 @@
define(
['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin',
'pgadmin.browser', 'backbone', 'backgrid', 'codemirror', 'backform',
'pgadmin.tools.debugger.ui', 'wcdocker', 'pgadmin.backform',
'pgadmin.backgrid', 'pgadmin.browser.frame'],
function($, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid, CodeMirror, Backform, get_function_arguments) {
pgAdmin = pgAdmin || window.pgAdmin || {};
var pgTools = pgAdmin.Tools = pgAdmin.Tools || {};
/* Return back, this has been called more than once */
if (pgAdmin.Tools.Debugger)
return pgAdmin.Tools.Debugger;
pgTools.Debugger = {
init: function() {
// We do not want to initialize the module multiple times.
if (this.initialized)
return;
this.initialized = true;
// Initialize the context menu to display the debugging options when user open the context menu for functions
pgBrowser.add_menus([{
name: 'direct_debugger', node: 'function', module: this,
applies: ['object', 'context'], callback: 'get_function_information',
category: 'Debugging', priority: 10, label: '{{ _('Debug') }}',
data: {object: 'function'}, icon: 'fa fa-arrow-circle-right',
enable: 'can_debug'
},{
name: 'global_debugger', node: 'function', module: this,
applies: ['object', 'context'], callback: 'check_func_debuggable',
category: 'Debugging', priority: 10, label: '{{ _('Set breakpoint') }}',
data: {object: 'function'}, icon: 'fa fa-arrow-circle-right',
enable: 'can_debug'
},{
name: 'procedure_direct_debugger', node: 'procedure', module: this,
applies: ['object', 'context'], callback: 'get_function_information',
category: 'Debugging', priority: 10, label: '{{ _('Debug') }}',
data: {object: 'procedure'}, icon: 'fa fa-arrow-circle-right',
enable: 'can_debug'
}, {
name: 'procedure_indirect_debugger', node: 'procedure', module: this,
applies: ['object', 'context'], callback: 'check_func_debuggable',
category: 'Debugging', priority: 10, label: '{{ _('Set breakpoint') }}',
data: {object: 'procedure'}, icon: 'fa fa-arrow-circle-right',
enable: 'can_debug'
}]);
// Create and load the new frame required for debugger panel
this.frame = new pgBrowser.Frame({
name: 'frm_debugger',
title: '{{ _('Debugger') }}',
width: 500,
isCloseable: true,
isPrivate: true,
url: 'about:blank'
});
this.frame.load(pgBrowser.docker);
},
// It will check weather the function is actually debuggable or not with pre-required condition.
can_debug: function(itemData, item, data) {
var t = pgBrowser.tree, i = item, d = itemData;
// To iterate over tree to check parent node
while (i) {
if ('catalog' == d._type) {
//Check if we are not child of catalog
return false;
}
i = t.hasParent(i) ? t.parent(i) : null;
d = i ? t.itemData(i) : null;
}
// Find the function is really available in database
var tree = pgBrowser.tree,
info = tree.selected(),
d_ = info && info.length == 1 ? tree.itemData(info) : undefined,
node = d_ && pgBrowser.Nodes[d_._type];
if (!d_)
return false;
var treeInfo = node.getTreeNodeHierarchy.apply(node, [info]);
// Must be a super user or object owner to create breakpoints of any kind
if (!(treeInfo.server.user.is_superuser || treeInfo.function.funcowner == treeInfo.server.user.name))
return false;
if (d_.language != 'plpgsql' && d_.language != 'edbspl') {
return false;
}
return true;
},
/*
For the direct debugging, we need to fetch the function information to display in the dialog so "generate_url"
will dynamically generate the URL from the server_id, database_id, schema_id and function id.
*/
generate_url: function(_url, treeInfo, node) {
var url = '{BASEURL}{URL}/{OBJTYPE}{REF}',
ref = '';
_.each(
_.sortBy(
_.values(
_.pick(treeInfo,
function(v, k, o) {
return (k != 'server-group');
})
),
function(o) { return o.priority; }
),
function(o) {
ref = S('%s/%s').sprintf(ref, encodeURI(o._id)).value();
});
var args = {
'URL': _url,
'BASEURL': '{{ url_for('debugger.index')}}',
'REF': ref,
'OBJTYPE': encodeURI(node.type)
};
return url.replace(/{(\w+)}/g, function(match, arg) {
return args[arg];
});
},
check_func_debuggable: function(args, item) {
var input = args || {},
t = pgBrowser.tree,
i = item || t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined,
node = d && pgBrowser.Nodes[d._type];
if (!d)
return;
var objName = d.label,
treeInfo = node.getTreeNodeHierarchy.apply(node, [i]),
_url = this.generate_url('init', treeInfo, node);
var self = this;
$.ajax({
url: _url,
cache: false,
success: function(res) {
self.start_global_debugger();
},
error: function(xhr, status, error) {
try {
var err = $.parseJSON(xhr.responseText);
if (err.success == 0) {
msg = S('{{ _(' + err.errormsg + ')}}').value();
Alertify.alert("{{ _('" + err.errormsg + "') }}");
}
} catch (e) {}
}
});
},
//Callback function when user start the indirect debugging ( Listen to another session to invoke the target )
start_global_debugger: function(args, item) {
// Initialize the target and create asynchronous connection and unique transaction ID
var t = pgBrowser.tree,
i = t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined,
node = d && pgBrowser.Nodes[d._type];
if (!d)
return;
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
if (d._type == "function") {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "indirect/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.function._id;
}
else {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "indirect/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.procedure._id;
}
$.ajax({
url: baseUrl,
method: 'GET',
success: function(res) {
var url = "{{ url_for('debugger.index') }}" + "direct/" + res.data.debuggerTransId;
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
});
},
error: function(e) {
Alertify.alert(
'Debugger target Initialize Error'
);
}
});
},
/*
Get the function information for the direct debugging to display the functions arguments and other informations
in the user input dialog
*/
get_function_information: function(args, item) {
var input = args || {},
t = pgBrowser.tree,
i = item || t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined,
node = d && pgBrowser.Nodes[d._type];
if (!d)
return;
var objName = d.label,
treeInfo = node.getTreeNodeHierarchy.apply(node, [i]),
_url = this.generate_url('init', treeInfo, node);
var self = this;
$.ajax({
url: _url,
cache: false,
success: function(res) {
// Open Alertify the dialog to take the input arguments from user if function having input arguments
if (res.data[0]['require_input']) {
get_function_arguments(res.data[0], 0);
}
else {
// Initialize the target and create asynchronous connection and unique transaction ID
// If there is no arguments to the functions then we should not ask for for function arguments and
// Directly open the panel
var t = pgBrowser.tree,
i = t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined,
node = d && pgBrowser.Nodes[d._type];
if (!d)
return;
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
if (d._type == "function") {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "direct/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.function._id;
}
else {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "direct/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.procedure._id;
}
$.ajax({
url: baseUrl,
method: 'GET',
success: function(res) {
var url = "{{ url_for('debugger.index') }}" + "direct/" + res.data.debuggerTransId;
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Register Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
});
},
error: function(e) {
Alertify.alert(
'Debugger target Initialize Error',
e.responseJSON.errormsg
);
}
});
}
},
error: function(xhr, status, error) {
try {
var err = $.parseJSON(xhr.responseText);
if (err.success == 0) {
msg = S('{{ _(' + err.errormsg + ')}}').value();
Alertify.alert("{{ _('" + err.errormsg + "') }}");
}
} catch (e) {}
}
});
}
};
return pgAdmin.Tools.Debugger;
});

View File

@@ -0,0 +1,657 @@
define(
['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin',
'pgadmin.browser', 'backbone', 'backgrid', 'codemirror', 'backform',
'wcdocker', 'pgadmin.backform', 'pgadmin.backgrid',
'pgadmin.browser.panel'],
function($, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid, CodeMirror, Backform ) {
/*
* Function used to return the respective Backgrid control based on the data type
* of function input argument.
*/
var cellFunction = function(model) {
var self = this,
variable_type = model.get("type");
// if variable type is an array then we need to render the custom control to take the input from user.
if (variable_type.indexOf("[]") !=-1) {
if (variable_type.indexOf("integer") != -1) {
return Backgrid.Extension.InputIntegerArrayCell;
}
return Backgrid.Extension.InputStringArrayCell;
}
switch(variable_type) {
case "bool":
return Backgrid.BooleanCell;
break;
case "integer":
// As we are getting this value as text from sqlite database so we need to type cast it.
if (model.get('value') != undefined) {
model.set({'value': parseInt(model.get('value'))},{silent:true});
}
return Backgrid.IntegerCell;
break;
case "real":
// As we are getting this value as text from sqlite database so we need to type cast it.
if (model.get('value') != undefined) {
model.set({'value': parseFloat(model.get('value'))} ,{silent:true});
}
return Backgrid.NumberCell;
break;
case "string":
return Backgrid.StringCell;
break;
case "date":
return Backgrid.DateCell;
break;
default:
return Backgrid.Cell;
break;
}
}
/*
* Function used to return the respective Backgrid string or boolean control based on the data type
* of function input argument.
*/
var cellExprControlFunction = function(model) {
var self = this,
variable_type = model.get("type");
if (variable_type.indexOf("[]") !=-1) {
return Backgrid.StringCell;
}
return Backgrid.BooleanCell;
}
/**
* DebuggerInputArgsModel used to represent input parameters for the function to debug
* for function objects.
**/
var DebuggerInputArgsModel = Backbone.Model.extend({
defaults: {
name: undefined,
type: undefined,
is_null: undefined,
expr: undefined,
value: undefined,
use_default: undefined,
default_value: undefined,
},
validate: function() {
if (_.isUndefined(this.get('value')) ||
_.isNull(this.get('value')) ||
String(this.get('value')).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Please enter some value!') }}';
this.errorModel.set('value', msg);
return msg;
} else {
this.errorModel.unset('value');
}
return null;
}
});
// Collection which contains the model for function informations.
var DebuggerInputArgCollections = Backbone.Collection.extend({
model: DebuggerInputArgsModel
});
// function will enable/disable the use_default column based on the value received.
var disableDefaultCell = function(d) {
if (d instanceof Backbone.Model) {
return d.get('use_default');
}
return false;
};
// Enable/Disable the control based on the array data type of the function input arguments
var disableExpressionControl = function(d) {
var argType = d.get('type');
if (d instanceof Backbone.Model) {
var argType = d.get('type');
if (argType.indexOf("[]") !=-1) {
return false;
}
return true;
}
};
var res = function(args, restart_debug) {
if (!Alertify.debuggerInputArgsDialog) {
Alertify.dialog('debuggerInputArgsDialog', function factory() {
return {
main:function(title, data, restart_debug) {
this.set('title', title);
this.data = data;
this.restart_debug = restart_debug;
// Variables to store the data sent from sqlite database
var func_args_data = this.func_args_data = [];
// As we are not getting pgBrowser.tree when we debug again so tree info will be updated from the server data
if (restart_debug == 0) {
var t = pgBrowser.tree,
i = t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined,
node = d && pgBrowser.Nodes[d._type];
if (!d)
return;
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
if (d._type == "function") {
// Get the existing function parameters available from sqlite database
var _Url = "{{ url_for('debugger.index') }}" + "get_arguments/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.function._id;
}
else {
// Get the existing function parameters available from sqlite database
var _Url = "{{ url_for('debugger.index') }}" + "get_arguments/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.procedure._id;
}
}
else {
// Get the existing function parameters available from sqlite database
var _Url = "{{ url_for('debugger.index') }}" + "get_arguments/" + this.data.server_id +
"/" + this.data.database_id + "/" + this.data.schema_id + "/" + this.data.function_id;
}
$.ajax({
url: _Url,
method: 'GET',
async: false,
success: function(res) {
if (res.data.args_count != 0) {
for (i = 0; i < res.data.result.length; i++) {
// Below will format the data to be stored in sqlite database
func_args_data.push({
'arg_id': res.data.result[i]['arg_id'],
'is_null': res.data.result[i]['is_null'],
'is_expression': res.data.result[i]['is_expression'],
'use_default': res.data.result[i]['use_default'],
'value': res.data.result[i]['value']
});
}
}
},
error: function(e) {
Alertify.alert(
'Debugger Set arguments error'
);
}
});
var argname, argtype, argmode, default_args_count, default_args, arg_cnt;
var value_header = Backgrid.HeaderCell.extend({
// Add fixed width to the "value" column
className: 'width_percent_25'
});
var def_val_list = [],
gridCols = [
{name: 'name', label:'Name', type:'text', editable: false, cell:'string' },
{name: 'type', label:'Type', type: 'text', editable: false, cell:'string' },
{name: 'is_null', label:'Null?', type: 'boolean', cell: 'boolean' },
{name: 'expr', label:'Expression?', type: 'boolean', cellFunction: cellExprControlFunction, editable: disableExpressionControl },
{name: 'value', label:'Value', type: 'text', editable: true, cellFunction: cellFunction, headerCell: value_header },
{name: 'use_default', label:'Use Default?', type: 'boolean', cell:"boolean", editable: disableDefaultCell },
{name: 'default_value', label:'Default value', type: 'text', editable: false, cell:'string' }
];
var my_obj = [];
var func_obj = [];
// Below will calculate the input argument id required to store in sqlite database
var input_arg_id = this.input_arg_id = [];
if (this.data['proargmodes'] != null) {
argmode_1 = this.data['proargmodes'].split(",");
for (k = 0; k < argmode_1.length; k++) {
if (argmode_1[k] == 'i' || argmode_1[k] == 'b') {
input_arg_id.push(k)
}
}
}
else {
argtype_1 = this.data['proargtypenames'].split(",");
for (k = 0; k < argtype_1.length; k++) {
input_arg_id.push(k)
}
}
argtype = this.data['proargtypenames'].split(",");
if (this.data['proargmodes'] != null) {
argmode = this.data['proargmodes'].split(",");
}
if (this.data['pronargdefaults']) {
default_args_count = this.data['pronargdefaults'];
default_args = this.data['proargdefaults'].split(",");
arg_cnt = default_args_count;
}
if (this.data['proargnames'] != null) {
argname = this.data['proargnames'].split(",");
// It will assign default values to "Default value" column
for (j = (argname.length - 1);j >= 0; j--) {
if (this.data['proargmodes'] != null) {
if (arg_cnt && (argmode[j] == 'i' || argmode[j] == 'b')) {
arg_cnt = arg_cnt - 1;
def_val_list[j] = default_args[arg_cnt]
}
else {
def_val_list[j] = "<No default value>";
}
}
else {
if (arg_cnt) {
arg_cnt = arg_cnt - 1;
def_val_list[j] = default_args[arg_cnt]
}
else {
def_val_list[j] = "<No default value>";
}
}
}
if (argtype.length != 0)
{
for (i = 0; i < argtype.length; i++) {
if (this.data['proargmodes'] != null) {
if (argmode[i] == 'i' || argmode[i] == 'b') {
var use_def_value = false
if (def_val_list[i] != "<No default value>") {
use_def_value = true;
}
my_obj.push({ "name": argname[i], "type": argtype[i], "use_default": use_def_value, "default_value": def_val_list[i]});
}
}
else {
var use_def_value = false
if (def_val_list[i] != "<No default value>") {
use_def_value = true;
}
my_obj.push({ "name": argname[i], "type": argtype[i], "use_default": use_def_value, "default_value": def_val_list[i]});
}
}
}
// Need to update the func_obj variable from sqlite database if available
// TODO: Need to check, how to update the value in Array fields....
if (func_args_data.length != 0) {
for (i = 0; i < func_args_data.length; i++) {
var index = func_args_data[i]['arg_id'];
func_obj.push({ "name": argname[index], "type": argtype[index], "is_null": func_args_data[i]['is_null'] ? true: false, "expr": func_args_data[i]['is_expression']? true: false, "value": func_args_data[i]['value'], "use_default": func_args_data[i]['use_default']? true: false, "default_value": def_val_list[index]});
}
}
}
else {
/*
Generate the name parameter if function do not have arguments name
like dbgparam1, dbgparam2 etc.
*/
var myargname = [];
for (i = 0; i < argtype.length; i++) {
myargname[i] = "dbgparam" + (i+1);
}
// If there is no default arguments
if (!this.data['pronargdefaults']) {
for (i = 0; i < argtype.length; i++) {
my_obj.push({ "name": myargname[i], "type": argtype[i], "use_default": false, "default_value": "<No default value>"});
def_val_list[i] = "<No default value>";
}
}
else {
// If there is default arguments
//Below logic will assign default values to "Default value" column
for (j = (myargname.length - 1);j >= 0; j--) {
if (this.data['proargmodes'] == null) {
if (arg_cnt) {
arg_cnt = arg_cnt - 1;
def_val_list[j] = default_args[arg_cnt]
}
else {
def_val_list[j] = "<No default value>";
}
}
else {
if (arg_cnt && (argmode[j] == 'i' || argmode[j] == 'b')) {
arg_cnt = arg_cnt - 1;
def_val_list[j] = default_args[arg_cnt]
}
else {
def_val_list[j] = "<No default value>";
}
}
}
for (i = 0; i < argtype.length; i++) {
if (this.data['proargmodes'] == null) {
var use_def_value = false
if (def_val_list[i] != "<No default value>") {
use_def_value = true;
}
my_obj.push({ "name": myargname[i], "type": argtype[i], "use_default": use_def_value, "default_value": def_val_list[i]});
}
else {
if (argmode[i] == 'i' || argmode[i] == 'b') {
var use_def_value = false
if (def_val_list[i] != "<No default value>") {
use_def_value = true;
}
my_obj.push({ "name": myargname[i], "type": argtype[i], "use_default": use_def_value, "default_value": def_val_list[i]});
}
}
}
}
// Need to update the func_obj variable from sqlite database if available
// TODO: Need to check, how to update the value in Array fields....
if (func_args_data.length != 0) {
for (i = 0; i < func_args_data.length; i++) {
var index = func_args_data[i]['arg_id'];
func_obj.push({ "name": myargname[index], "type": argtype[index], "is_null": func_args_data[i]['is_null'] ? true: false, "expr": func_args_data[i]['is_expression']? true: false, "value": func_args_data[i]['value'], "use_default": func_args_data[i]['use_default']? true: false, "default_value": def_val_list[index]});
}
}
}
// Check if the arguments already available in the sqlite database then we should use the existing arguments
if (func_args_data.length == 0) {
var debuggerInputArgsColl = this.debuggerInputArgsColl = new DebuggerInputArgCollections(my_obj);
}
else {
var debuggerInputArgsColl = this.debuggerInputArgsColl = new DebuggerInputArgCollections(func_obj);
}
// Initialize a new Grid instance
if (this.grid) {
this.grid.remove();
this.grid = null;
}
var grid = this.grid = new Backgrid.Grid({
columns: gridCols,
collection: debuggerInputArgsColl,
className: "backgrid table-bordered"
});
grid.render();
$(this.elements.content).html(grid.el);
},
setup:function() {
return {
buttons:[{ text: "Debug", key: 27, className: "btn btn-primary" },
{ text: "Cancel", key: 27, className: "btn btn-primary" }],
options: { modal: 0, resizable: true }
};
},
// Callback functions when click on the buttons of the Alertify dialogs
callback: function(e) {
if (e.button.text === "Debug") {
// Initialize the target once the debug button is clicked and
// create asynchronous connection and unique transaction ID
var self = this;
// If the debugging is started again then treeInfo is already stored in this.data so we can use the same.
if (self.restart_debug == 0) {
var t = pgBrowser.tree,
i = t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined,
node = d && pgBrowser.Nodes[d._type];
if (!d)
return;
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
}
var args_value_list = [];
var sqlite_func_args_list = this.sqlite_func_args_list = [];
var int_count = 0;
this.grid.collection.each(function(m) {
// TODO: Removed temporary for testing.....
// Check if value is set to NULL then we should ignore the value field
if (m.get('is_null')) {
args_value_list.push({ 'name': m.get('name'),
'type': m.get('type'),
'value': 'NULL'});
}
else {
// Check if default value to be used or not
if (m.get('use_default')) {
args_value_list.push({ 'name': m.get('name'),
'type': m.get('type'),
'value': m.get('default_value')});
}
else {
args_value_list.push({ 'name': m.get('name'),
'type': m.get('type'),
'value': m.get('value')});
}
}
if (self.restart_debug == 0) {
// Below will format the data to be stored in sqlite database
sqlite_func_args_list.push({
'server_id': treeInfo.server._id,
'database_id': treeInfo.database._id,
'schema_id': treeInfo.schema._id ,
'function_id': d._type == "function" ? treeInfo.function._id : treeInfo.procedure._id,
'arg_id': self.input_arg_id[int_count],
'is_null': m.get('is_null') ? 1 : 0,
'is_expression': m.get('expr') ? 1 : 0,
'use_default': m.get('use_default') ? 1 : 0,
'value': m.get('value')
});
}
else {
// Below will format the data to be stored in sqlite database
sqlite_func_args_list.push({
'server_id': self.data.server_id,
'database_id': self.data.database_id,
'schema_id': self.data.schema_id ,
'function_id': self.data.function_id,
'arg_id': self.input_arg_id[int_count],
'is_null': m.get('is_null') ? 1 : 0,
'is_expression': m.get('expr') ? 1 : 0,
'use_default': m.get('use_default') ? 1 : 0,
'value': m.get('value')
});
}
int_count = int_count + 1;
});
// If debugging is not started again then we should initialize the target otherwise not
if (self.restart_debug == 0) {
if (d._type == "function") {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "direct/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.function._id;
}
else {
var baseUrl = "{{ url_for('debugger.index') }}" + "initialize_target/" + "direct/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.procedure._id;
}
$.ajax({
url: baseUrl,
method: 'POST',
data:{'data':JSON.stringify(args_value_list)},
success: function(res) {
var url = "{{ url_for('debugger.index') }}" + "direct/" + res.data.debuggerTransId;
pgBrowser.Events.once(
'pgadmin-browser:frame:urlloaded:frm_debugger', function(frame) {
frame.openURL(url);
});
// Create the debugger panel as per the data received from user input dialog.
var dashboardPanel = pgBrowser.docker.findPanels(
'dashboard'
),
panel = pgBrowser.docker.addPanel(
'frm_debugger', wcDocker.DOCK.STACKED, dashboardPanel[0]
);
panel.focus();
// Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = "{{ url_for('debugger.index') }}" + "close/" + res.data.debuggerTransId;
$.ajax({
url: closeUrl,
method: 'GET'
});
});
if (d._type == "function") {
var _Url = "{{ url_for('debugger.index') }}" + "set_arguments/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.function._id;
}
else {
var _Url = "{{ url_for('debugger.index') }}" + "set_arguments/" + treeInfo.server._id +
"/" + treeInfo.database._id + "/" + treeInfo.schema._id + "/" + treeInfo.procedure._id;
}
$.ajax({
url: _Url,
method: 'POST',
data:{'data':JSON.stringify(sqlite_func_args_list)},
success: function(res) {
},
error: function(e) {
Alertify.alert(
'Debugger Set arguments error'
);
}
});
},
error: function(e) {
Alertify.alert(
'Debugger target Initialize Error',
e.responseJSON.errormsg
);
}
});
}
else {
// If the debugging is started again then we should only set the arguments and start the listener again
var baseUrl = "{{ url_for('debugger.index') }}" + "start_listener/" + self.data.trans_id;
$.ajax({
url: baseUrl,
method: 'POST',
data:{'data':JSON.stringify(args_value_list)},
success: function(res) {
//TODO: Anything required ? .....
},
error: function(e) {
Alertify.alert(
'Debugger listener starting error',
e.responseJSON.errormsg
);
}
});
// Set the new input arguments given by the user during debugging
var _Url = "{{ url_for('debugger.index') }}" + "set_arguments/" + self.data.server_id +
"/" + self.data.database_id + "/" + self.data.schema_id + "/" + self.data.function_id;
$.ajax({
url: _Url,
method: 'POST',
data:{'data':JSON.stringify(sqlite_func_args_list)},
success: function(res) {
},
error: function(e) {
Alertify.alert(
'Debugger Set arguments error'
);
}
});
}
return true;
}
if (e.button.text === "Cancel") {
//close the dialog...
return false;
}
},
build:function() {
},
prepare:function() {
/*
If we already have data available in sqlite database then we should enable the debug button otherwise
disable the debug button.
*/
if (this.func_args_data.length == 0) {
this.__internal.buttons[0].element.disabled = true;
}
else {
this.__internal.buttons[0].element.disabled = false;
}
/*
Listen to the grid change event so that if any value changed by user then we can enable/disable the
debug button.
*/
this.grid.listenTo(this.debuggerInputArgsColl,"backgrid:edited",
(function(obj) {
return function() {
var self = this;
var enable_btn = false;
for (i = 0; i < this.collection.length; i++ ) {
// TODO: Need to check the "NULL" and "Expression" column value to enable/disable the "Debug" button
if (this.collection.models[i].get('value') == "" ||
this.collection.models[i].get('value') == null ||
this.collection.models[i].get('value') == undefined) {
enable_btn = true;
if (this.collection.models[i].get('use_default')) {
obj.__internal.buttons[0].element.disabled = false;
}
else{
obj.__internal.buttons[0].element.disabled = true;
break;
}
}
}
if (!enable_btn)
obj.__internal.buttons[0].element.disabled = false;
}
}
)(this)
);
}
};
});
}
Alertify.debuggerInputArgsDialog('Debugger',args, restart_debug).resizeTo('60%', '60%');
};
return res;
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
{### Create executer function for edb spl function debugging ###}
{% set inside_loop = {'value': False} %}
{% if lan_name == 'edbspl' %}
{% set useAnonymousBlock = "true" %}
{% if not is_func %}
{% set str_statement = "\tEXEC " ~ func_name %}
{% elif ret_type == 'void' %}
{% set str_statement = "\tPERFORM " ~ func_name %}
{% else %}
{% set resultVar = "v_retVal" %}
{% set str_statement = "\t" ~ resultVar ~ " := " ~ func_name %}
{% set str_declare = str_declare ~ "\t" ~ resultVar ~ " " ~ ret_type ~ ";\n" %}
{% set str_result = "\tDBMS_OUTPUT.PUT_LINE(E'\\n\\nResult:\\n--------\\n' || " ~ resultVar ~ "::text || E'\\n\\nNOTE: This is the result generated during the function execution by the debugger.\\n');\n" %}
{% endif %}
{% else %}
{% if ret_type == 'record' %}
{% set str_statement = "\tSELECT " ~ func_name %}
{% else %}
{% set str_statement = "\tSELECT * FROM " ~ func_name %}
{% endif %}
{% endif %}
{% set firstProceesed = "false" %}
{% set input_value_index = 0 %}
{% if arg_type|length > 0 %}
{% set str_statement = str_statement ~ "(" %}
{% for arg_mode in args_mode %}
{% if useAnonymousBlock == "true" and (arg_mode == 'o' or arg_mode == 'b') %}
{% set strParam = "p_param" ~ (loop.index - 1) %}
{% set str_declare = str_declare ~ "\t" ~ strParam ~ " " ~ arg_type[loop.index - 1] %}
{% if arg_mode == 'b' %}
{### TODO: to check for Null parameters received from client ###}
{% if data[input_value_index]['type'] == 'text' and data[input_value_index]['value'] != 'NULL' %}
{% set tmp_val = data[input_value_index]['value']|qtLiteral %}
{% set str_declare = str_declare ~ " := " ~ strParam ~ " " ~ tmp_val ~ "::" ~ data[input_value_index]['type'] %}
{% else %}
{% set str_declare = str_declare ~ " := " ~ strParam ~ " " ~ data[input_value_index]['value'] ~ "::" ~ data[input_value_index]['type'] %}
{% endif %}
{% set input_value_index = input_value_index + 1 %}
{% endif %}
{% set str_declare = str_declare ~ ";\n" %}
{% if firstProceesed == "true" %}
{% set str_statement = str_statement ~ ", " %}
{% endif %}
{% set firstProceesed = "true" %}
{% set str_statement = str_statement ~ strParam %}
{% elif arg_mode != 'o' %}
{% if firstProceesed == "true" %}
{% set str_statement = str_statement ~ ", " %}
{% endif %}
{% set firstProceesed = "true" %}
{% if arg_mode == 'v' %}
{% set str_statement = str_statement ~ "VARIADIC " %}
{% endif %}
{### TODO: to check for Null parameters received from client ###}
{% if data[input_value_index]['type'] == 'text' and data[input_value_index]['value'] != 'NULL' %}
{% set tmp_var = data[input_value_index]['value']|qtLiteral %}
{% set str_statement = str_statement ~ tmp_var ~ "::" ~ data[input_value_index]['type'] %}
{% else %}
{% set str_statement = str_statement ~ data[input_value_index]['value'] ~ "::" ~ data[input_value_index]['type'] %}
{% endif %}
{% set input_value_index = input_value_index + 1 %}
{% endif %}
{% if loop.last %}
{% set str_statement = str_statement ~ ")" %}
{% set strQuery = str_statement %}
{% if useAnonymousBlock == "true" %}
{% set strQuery = "DECLARE\n" ~ str_declare ~ "BEGIN\n" ~ str_statement ~ ";\n" ~ str_result ~ "END;" %}
{% endif %}
{{ strQuery }}
{% if inside_loop.update({'value': True}) %} {% endif %}
{% endif %}
{% endfor %}
{% elif not is_func and lan_name == 'edbspl' %}
{% set strQuery = str_statement %}
{% if useAnonymousBlock == "true" %}
{% set strQuery = "DECLARE\n" ~ str_declare ~ "BEGIN\n" ~ str_statement ~ ";\n" ~ str_result ~ "END;" %}
{% endif %}
{% else %}
{% set strQuery = str_statement ~ "()" %}
{% if useAnonymousBlock == "true" %}
{% set strQuery = "DECLARE\n" ~ str_declare ~ "BEGIN\n" ~ str_statement ~ ";\n" ~ str_result ~ "END;" %}
{% endif %}
{% endif %}
{### Return final query formed with above condition ###}
{% if not inside_loop.value %}
{{ strQuery }}
{% endif %}

View File

@@ -0,0 +1,32 @@
{### Create executer function for plpgsql function debugging ###}
{% if not is_func %}
EXEC {{ func_name }} (
{% elif ret_type == 'record' %}
SELECT {{ func_name }} (
{% else %}
SELECT * FROM {{ func_name }} (
{% endif %}
{% if data %}
{% for dict_item in data %}
{% if 'type' in dict_item and 'value' in dict_item %}
{% if dict_item['type'] == 'text' and dict_item['value'] != 'NULL' %}
{{ dict_item['value']|qtLiteral }}::{{ dict_item['type'] }}{% if not loop.last %}, {% endif %}
{% elif dict_item['type'] == 'text' and dict_item['value'] == 'NULL' %}
{{ dict_item['value'] }}::{{ dict_item['type'] }}{% if not loop.last %}, {% endif %}
{% else %}
{% if '[]' in dict_item['type'] %}
ARRAY[
{% for dict_list in dict_item['value'] %}
{% if 'value' in dict_list %}
{{ dict_list['value']|qtLiteral }}{% if not loop.last %}, {% endif %}
{% endif %}
{% endfor %}
]::{{ dict_item['type'] }}
{% else %} {{ dict_item['value'] }}::{{ dict_item['type'] }}
{% endif %} {% if not loop.last %}, {% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
)

View File

@@ -0,0 +1,64 @@
{### To fetch debug function information ###}
SELECT
p.proname AS name, p.prosrc, l.lanname, p.proretset, p.prorettype, y.typname AS rettype,
CASE WHEN proallargtypes IS NOT NULL THEN
pg_catalog.array_to_string(ARRAY(
SELECT
pg_catalog.format_type(p.proallargtypes[s.i], NULL)
FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(
p.proallargtypes, 1)) AS s(i)), ',')
ELSE
pg_catalog.array_to_string(ARRAY(
SELECT
pg_catalog.format_type(p.proargtypes[s.i], NULL)
FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(
p.proargtypes, 1)) AS s(i)), ',')
END AS proargtypenames,
CASE WHEN proallargtypes IS NOT NULL THEN
pg_catalog.array_to_string(ARRAY(
SELECT proallargtypes[s.i] FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(proallargtypes, 1)) s(i)), ',')
ELSE
pg_catalog.array_to_string(ARRAY(
SELECT proargtypes[s.i] FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(proargtypes, 1)) s(i)), ',')
END AS proargtypes,
pg_catalog.array_to_string(p.proargnames, ',') AS proargnames,
pg_catalog.array_to_string(proargmodes, ',') AS proargmodes,
{% if is_ppas_database %}
CASE WHEN n.nspparent <> 0 THEN n.oid ELSE 0 END AS pkg,
CASE WHEN n.nspparent <> 0 THEN n.nspname ELSE '' END AS pkgname,
CASE WHEN n.nspparent <> 0 THEN (SELECT oid FROM pg_proc WHERE pronamespace=n.oid AND proname='cons') ELSE 0 END AS pkgconsoid,
CASE WHEN n.nspparent <> 0 THEN g.oid ELSE n.oid END AS schema,
CASE WHEN n.nspparent <> 0 THEN g.nspname ELSE n.nspname END AS schemaname,
NOT (l.lanname = 'edbspl' AND protype = '1') AS isfunc,
{%else%}
0 AS pkg,
'' AS pkgname,
0 AS pkgconsoid,
n.oid AS schema,
n.nspname AS schemaname,
true AS isfunc,
{%endif%}
pg_catalog.pg_get_function_identity_arguments(p.oid) AS signature,
{% if hasFeatureFunctionDefaults %}
pg_catalog.pg_get_expr(p.proargdefaults, 'pg_catalog.pg_class'::regclass, false) AS proargdefaults,
p.pronargdefaults
{%else%}
'' AS proargdefaults, 0 AS pronargdefaults
{%endif%}
FROM
pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid
LEFT JOIN pg_catalog.pg_language l ON p.prolang = l.oid
LEFT JOIN pg_catalog.pg_type y ON p.prorettype = y.oid
{% if is_ppas_database %}
LEFT JOIN pg_catalog.pg_namespace g ON n.nspparent = g.oid
{% endif %}
{% if fid %}
WHERE p.oid = {{fid}}::int;
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Abort the target for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_abort_target({{session_id}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Add EDB breakpoints for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_set_global_breakpoint({{session_id}}::int, {{package_oid}}::int, {{function_oid}}::OID, -1, {{target_oid}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Add PG breakpoint for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_set_global_breakpoint({{session_id}}, {{function_oid}}, -1, NULL)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Attach the target to port for debugging ###}
{% if port %}
SELECT * FROM pldbg_attach_to_port({{port}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Clear breakpoints for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_drop_breakpoint({{session_id}}::int, {{poid}}::OID, {{foid}}::OID, {{line_number}}::int)
{% endif %}

View File

@@ -0,0 +1,11 @@
{### Continue for debugging ###}
{% if session_id %}
SELECT
p.pkg AS pkg, p.func AS func, p.targetName AS targetName,
p.linenumber AS linenumber, pldbg_get_source({{session_id}}::INTEGER, p.pkg, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func AND s.pkg = p.pkg) AS args
FROM pldbg_continue({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,2 @@
{### Create listener for debugging ###}
SELECT * from pldbg_create_listener()

View File

@@ -0,0 +1,4 @@
{### Debug execute target for plpgsql function ###}
{% if function_oid %}
SELECT plpgsql_oid_debug({{packge_oid}}, {{function_oid}})
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Debug Initialization for plpgsql function ###}
{% if packge_init_oid %}
SELECT plpgsql_oid_debug({{packge_oid}}::OID, {{packge_init_oid}}::OID)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Debug execute target for EDB spl function ###}
{% if function_oid %}
SELECT edb_oid_debug({{packge_oid}}, {{function_oid}})
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Debug Initialization for EDB spl function ###}
{% if packge_init_oid %}
SELECT edb_oid_debug({{packge_oid}}::OID, {{packge_init_oid}}::OID)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Change the variable value and submit during debugging ###}
{% if session_id %}
SELECT * FROM pldbg_deposit_value({{session_id}}::int, {{var_name|qtLiteral}}, {{line_number}}, {{val|qtLiteral}})
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Get the breakpoint information for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_get_breakpoints({{session_id}}::int)
{% endif %}

View File

@@ -0,0 +1,64 @@
{### To fetch debug function information ###}
SELECT
p.proname AS name, l.lanname, p.proretset, p.prorettype, y.typname AS rettype,
CASE WHEN proallargtypes IS NOT NULL THEN
pg_catalog.array_to_string(ARRAY(
SELECT
pg_catalog.format_type(p.proallargtypes[s.i], NULL)
FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(
p.proallargtypes, 1)) AS s(i)), ',')
ELSE
pg_catalog.array_to_string(ARRAY(
SELECT
pg_catalog.format_type(p.proargtypes[s.i], NULL)
FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(
p.proargtypes, 1)) AS s(i)), ',')
END AS proargtypenames,
CASE WHEN proallargtypes IS NOT NULL THEN
pg_catalog.array_to_string(ARRAY(
SELECT proallargtypes[s.i] FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(proallargtypes, 1)) s(i)), ',')
ELSE
pg_catalog.array_to_string(ARRAY(
SELECT proargtypes[s.i] FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(proargtypes, 1)) s(i)), ',')
END AS proargtypes,
pg_catalog.array_to_string(p.proargnames, ',') AS proargnames,
pg_catalog.array_to_string(proargmodes, ',') AS proargmodes,
{% if is_ppas_database %}
CASE WHEN n.nspparent <> 0 THEN n.oid ELSE 0 END AS pkg,
CASE WHEN n.nspparent <> 0 THEN n.nspname ELSE '' END AS pkgname,
CASE WHEN n.nspparent <> 0 THEN (SELECT oid FROM pg_proc WHERE pronamespace=n.oid AND proname='cons') ELSE 0 END AS pkgconsoid,
CASE WHEN n.nspparent <> 0 THEN g.oid ELSE n.oid END AS schema,
CASE WHEN n.nspparent <> 0 THEN g.nspname ELSE n.nspname END AS schemaname,
NOT (l.lanname = 'edbspl' AND protype = '1') AS isfunc,
{%else%}
0 AS pkg,
'' AS pkgname,
0 AS pkgconsoid,
n.oid AS schema,
n.nspname AS schemaname,
true AS isfunc,
{%endif%}
pg_catalog.pg_get_function_identity_arguments(p.oid) AS signature,
{% if hasFeatureFunctionDefaults %}
pg_catalog.pg_get_expr(p.proargdefaults, 'pg_catalog.pg_class'::regclass, false) AS proargdefaults,
p.pronargdefaults
{%else%}
'' AS proargdefaults, 0 AS pronargdefaults
{%endif%}
FROM
pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid
LEFT JOIN pg_catalog.pg_language l ON p.prolang = l.oid
LEFT JOIN pg_catalog.pg_type y ON p.prorettype = y.oid
{% if is_ppas_database %}
LEFT JOIN pg_catalog.pg_namespace g ON n.nspparent = g.oid
{% endif %}
{% if fid %}
WHERE p.oid = {{fid}}::int;
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Get the stack information for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_get_stack({{session_id}}::int) ORDER BY level
{% endif %}

View File

@@ -0,0 +1,8 @@
{### Get the variables information for debugging ###}
{% if session_id %}
SELECT
name, varClass, value,
pg_catalog.format_type(dtype, NULL) as dtype, isconst
FROM pldbg_get_variables({{session_id}}::int)
ORDER BY varClass
{% endif %}

View File

@@ -0,0 +1,12 @@
{### select the frame to debug the function ###}
{% if session_id and frame_id %}
SELECT
p.pkg AS pkg, p.func AS func, p.targetName AS targetName,
p.linenumber AS linenumber,
CASE WHEN p.func <> 0 THEN pldbg_get_source({{session_id}}::INTEGER, p.func, p.pkg) ELSE '<No source available>' END AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func AND s.pkg = p.pkg) AS args
FROM pldbg_select_frame({{session_id}}::INTEGER, {{frame_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Set the breakpoints for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_set_breakpoint({{session_id}}::int ,{{poid}}::OID, {{foid}}::OID, {{line_number}}::int)
{% endif %}

View File

@@ -0,0 +1,11 @@
{### Step into function for debugging ###}
{% if session_id %}
SELECT
p.pkg AS pkg, p.func AS func, p.targetName AS targetName,
p.linenumber AS linenumber, pldbg_get_source({{session_id}}::INTEGER, p.pkg, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func AND s.pkg = p.pkg) AS args
FROM pldbg_step_into({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,11 @@
{### Step over function for debugging ###}
{% if session_id %}
SELECT
p.pkg AS pkg, p.func AS func, p.targetName AS targetName,
p.linenumber AS linenumber, pldbg_get_source({{session_id}}::INTEGER, p.pkg, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func AND s.pkg = p.pkg) AS args
FROM pldbg_step_over({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,11 @@
{### select the frame to debug the function ###}
{% if session_id %}
SELECT
p.pkg AS pkg, p.func AS func, p.targetName AS targetName,
p.linenumber AS linenumber, pldbg_get_source({{session_id}}::INTEGER, p.pkg, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func AND s.pkg = p.pkg) AS args
FROM pldbg_wait_for_breakpoint({{session_id}}::INTEGER) p;
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Wait for the target for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_wait_for_target({{session_id}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Abort the target for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_abort_target({{session_id}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Add EDB breakpoints for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_set_global_breakpoint({{session_id}}::int, {{package_oid}}::int, {{function_oid}}::OID, -1, {{target_oid}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Add PG breakpoint for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_set_global_breakpoint({{session_id}}, {{function_oid}}, -1, NULL)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Attach the target to port for debugging ###}
{% if port %}
SELECT * FROM pldbg_attach_to_port({{port}}::int)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Clear breakpoints for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_drop_breakpoint({{session_id}}::int, {{foid}}::OID, {{line_number}}::int)
{% endif %}

View File

@@ -0,0 +1,11 @@
{### Continue for debugging ###}
{% if session_id %}
SELECT
p.func, p.targetName, p.linenumber,
pldbg_get_source({{session_id}}::INTEGER, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func) AS args
FROM pldbg_continue({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,2 @@
{### Create listener for debugging ###}
SELECT * from pldbg_create_listener()

View File

@@ -0,0 +1,4 @@
{### Debug execute target for plpgsql function ###}
{% if function_oid %}
SELECT plpgsql_oid_debug({{function_oid}})
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Debug Initialization for plpgsql function ###}
{% if packge_init_oid %}
SELECT plpgsql_oid_debug({{packge_init_oid}}::OID)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Debug execute target for EDB spl function ###}
{% if function_oid %}
SELECT edb_oid_debug({{function_oid}})
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Debug Initialization for EDB spl function ###}
{% if packge_init_oid %}
SELECT edb_oid_debug({{packge_init_oid}}::OID)
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Change the variable value and submit during debugging ###}
{% if session_id %}
SELECT * FROM pldbg_deposit_value({{session_id}}::int, {{var_name|qtLiteral }}, {{line_number}}, {{val|qtLiteral}})
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Get the breakpoint information for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_get_breakpoints({{session_id}}::int)
{% endif %}

View File

@@ -0,0 +1,64 @@
{### To fetch debug function information ###}
SELECT
p.proname AS name, l.lanname, p.proretset, p.prorettype, y.typname AS rettype,
CASE WHEN proallargtypes IS NOT NULL THEN
pg_catalog.array_to_string(ARRAY(
SELECT
pg_catalog.format_type(p.proallargtypes[s.i], NULL)
FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(
p.proallargtypes, 1)) AS s(i)), ',')
ELSE
pg_catalog.array_to_string(ARRAY(
SELECT
pg_catalog.format_type(p.proargtypes[s.i], NULL)
FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(
p.proargtypes, 1)) AS s(i)), ',')
END AS proargtypenames,
CASE WHEN proallargtypes IS NOT NULL THEN
pg_catalog.array_to_string(ARRAY(
SELECT proallargtypes[s.i] FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(proallargtypes, 1)) s(i)), ',')
ELSE
pg_catalog.array_to_string(ARRAY(
SELECT proargtypes[s.i] FROM
pg_catalog.generate_series(0, pg_catalog.array_upper(proargtypes, 1)) s(i)), ',')
END AS proargtypes,
pg_catalog.array_to_string(p.proargnames, ',') AS proargnames,
pg_catalog.array_to_string(proargmodes, ',') AS proargmodes,
{% if is_ppas_database %}
CASE WHEN n.nspparent <> 0 THEN n.oid ELSE 0 END AS pkg,
CASE WHEN n.nspparent <> 0 THEN n.nspname ELSE '' END AS pkgname,
CASE WHEN n.nspparent <> 0 THEN (SELECT oid FROM pg_proc WHERE pronamespace=n.oid AND proname='cons') ELSE 0 END AS pkgconsoid,
CASE WHEN n.nspparent <> 0 THEN g.oid ELSE n.oid END AS schema,
CASE WHEN n.nspparent <> 0 THEN g.nspname ELSE n.nspname END AS schemaname,
NOT (l.lanname = 'edbspl' AND protype = '1') AS isfunc,
{%else%}
0 AS pkg,
'' AS pkgname,
0 AS pkgconsoid,
n.oid AS schema,
n.nspname AS schemaname,
true AS isfunc,
{%endif%}
pg_catalog.pg_get_function_identity_arguments(p.oid) AS signature,
{% if hasFeatureFunctionDefaults %}
pg_catalog.pg_get_expr(p.proargdefaults, 'pg_catalog.pg_class'::regclass, false) AS proargdefaults,
p.pronargdefaults
{%else%}
'' AS proargdefaults, 0 AS pronargdefaults
{%endif%}
FROM
pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid
LEFT JOIN pg_catalog.pg_language l ON p.prolang = l.oid
LEFT JOIN pg_catalog.pg_type y ON p.prorettype = y.oid
{% if is_ppas_database %}
LEFT JOIN pg_catalog.pg_namespace g ON n.nspparent = g.oid
{% endif %}
{% if fid %}
WHERE p.oid = {{fid}}::int;
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Get the stack information for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_get_stack({{session_id}}::int) ORDER BY level
{% endif %}

View File

@@ -0,0 +1,8 @@
{### Get the variables information for debugging ###}
{% if session_id %}
SELECT
name, varClass, value,
pg_catalog.format_type(dtype, NULL) as dtype, isconst
FROM pldbg_get_variables({{session_id}}::int)
ORDER BY varClass
{% endif %}

View File

@@ -0,0 +1,11 @@
{### select the frame to debug the function ###}
{% if session_id %}
SELECT
p.func AS func, p.targetName AS targetName, p.linenumber AS linenumber,
CASE WHEN p.func <> 0 THEN pldbg_get_source({{session_id}}::INTEGER, p.func) ELSE '<No source available>' END AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func) AS args
FROM pldbg_select_frame({{session_id}}::INTEGER, {{frame_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Set the breakpoints for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_set_breakpoint({{session_id}}::int, {{foid}}::OID,{{line_number}}::int)
{% endif %}

View File

@@ -0,0 +1,11 @@
{### Step into function for debugging ###}
{% if session_id %}
SELECT
p.func, p.targetName, p.linenumber,
pldbg_get_source({{session_id}}::INTEGER, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func) AS args
FROM pldbg_step_into({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,11 @@
{### Step over function for debugging ###}
{% if session_id %}
SELECT
p.func, p.targetName, p.linenumber,
pldbg_get_source({{session_id}}::INTEGER, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func) AS args
FROM pldbg_step_over({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,12 @@
{### select the frame to debug the function ###}
{% if session_id %}
SELECT
p.func AS func, p.targetName AS targetName,
p.linenumber AS linenumber,
pldbg_get_source({{session_id}}::INTEGER, p.func) AS src,
(SELECT
s.args
FROM pldbg_get_stack({{session_id}}::INTEGER) s
WHERE s.func = p.func) AS args
FROM pldbg_wait_for_breakpoint({{session_id}}::INTEGER) p
{% endif %}

View File

@@ -0,0 +1,4 @@
{### Wait for the target for debugging ###}
{% if session_id %}
SELECT * FROM pldbg_wait_for_target({{session_id}}::int)
{% endif %}