mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Procedural language debugger.
This commit is contained in:
1322
web/pgadmin/tools/debugger/__init__.py
Normal file
1322
web/pgadmin/tools/debugger/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
72
web/pgadmin/tools/debugger/static/css/debugger.css
Normal file
72
web/pgadmin/tools/debugger/static/css/debugger.css
Normal 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;
|
||||
}
|
63
web/pgadmin/tools/debugger/templates/debugger/direct.html
Normal file
63
web/pgadmin/tools/debugger/templates/debugger/direct.html
Normal 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 %}
|
329
web/pgadmin/tools/debugger/templates/debugger/js/debugger.js
Normal file
329
web/pgadmin/tools/debugger/templates/debugger/js/debugger.js
Normal 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;
|
||||
});
|
657
web/pgadmin/tools/debugger/templates/debugger/js/debugger_ui.js
Normal file
657
web/pgadmin/tools/debugger/templates/debugger/js/debugger_ui.js
Normal 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;
|
||||
});
|
1388
web/pgadmin/tools/debugger/templates/debugger/js/direct.js
Normal file
1388
web/pgadmin/tools/debugger/templates/debugger/js/direct.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 %}
|
@@ -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 %}
|
||||
)
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Abort the target for debugging ###}
|
||||
{% if session_id %}
|
||||
SELECT * FROM pldbg_abort_target({{session_id}}::int)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Attach the target to port for debugging ###}
|
||||
{% if port %}
|
||||
SELECT * FROM pldbg_attach_to_port({{port}}::int)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,2 @@
|
||||
{### Create listener for debugging ###}
|
||||
SELECT * from pldbg_create_listener()
|
@@ -0,0 +1,4 @@
|
||||
{### Debug execute target for plpgsql function ###}
|
||||
{% if function_oid %}
|
||||
SELECT plpgsql_oid_debug({{packge_oid}}, {{function_oid}})
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Debug execute target for EDB spl function ###}
|
||||
{% if function_oid %}
|
||||
SELECT edb_oid_debug({{packge_oid}}, {{function_oid}})
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Get the breakpoint information for debugging ###}
|
||||
{% if session_id %}
|
||||
SELECT * FROM pldbg_get_breakpoints({{session_id}}::int)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Wait for the target for debugging ###}
|
||||
{% if session_id %}
|
||||
SELECT * FROM pldbg_wait_for_target({{session_id}}::int)
|
||||
{% endif %}
|
@@ -0,0 +1,4 @@
|
||||
{### Abort the target for debugging ###}
|
||||
{% if session_id %}
|
||||
SELECT * FROM pldbg_abort_target({{session_id}}::int)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Attach the target to port for debugging ###}
|
||||
{% if port %}
|
||||
SELECT * FROM pldbg_attach_to_port({{port}}::int)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,2 @@
|
||||
{### Create listener for debugging ###}
|
||||
SELECT * from pldbg_create_listener()
|
@@ -0,0 +1,4 @@
|
||||
{### Debug execute target for plpgsql function ###}
|
||||
{% if function_oid %}
|
||||
SELECT plpgsql_oid_debug({{function_oid}})
|
||||
{% endif %}
|
@@ -0,0 +1,4 @@
|
||||
{### Debug Initialization for plpgsql function ###}
|
||||
{% if packge_init_oid %}
|
||||
SELECT plpgsql_oid_debug({{packge_init_oid}}::OID)
|
||||
{% endif %}
|
@@ -0,0 +1,4 @@
|
||||
{### Debug execute target for EDB spl function ###}
|
||||
{% if function_oid %}
|
||||
SELECT edb_oid_debug({{function_oid}})
|
||||
{% endif %}
|
@@ -0,0 +1,4 @@
|
||||
{### Debug Initialization for EDB spl function ###}
|
||||
{% if packge_init_oid %}
|
||||
SELECT edb_oid_debug({{packge_init_oid}}::OID)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Get the breakpoint information for debugging ###}
|
||||
{% if session_id %}
|
||||
SELECT * FROM pldbg_get_breakpoints({{session_id}}::int)
|
||||
{% endif %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -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 %}
|
@@ -0,0 +1,4 @@
|
||||
{### Wait for the target for debugging ###}
|
||||
{% if session_id %}
|
||||
SELECT * FROM pldbg_wait_for_target({{session_id}}::int)
|
||||
{% endif %}
|
Reference in New Issue
Block a user