diff --git a/docs/en_US/debugger.rst b/docs/en_US/debugger.rst
index 99fcaa85c..6c646100f 100644
--- a/docs/en_US/debugger.rst
+++ b/docs/en_US/debugger.rst
@@ -81,6 +81,8 @@ Use the fields on the *Debugger* dialog to provide a value for each parameter:
Provide values required by the program, and click the *Debug* button to start
stepping through the program.
+The values of the arguments provided here are saved. The values will be pre-filled
+next time the dialog opens. To clear the values, use the *Clear All* button.
.. image:: images/debug_step_in.png
:alt: Debugger step-in demo
diff --git a/docs/en_US/images/debug_params.png b/docs/en_US/images/debug_params.png
old mode 100755
new mode 100644
index 8915fae49..dcc6c630f
Binary files a/docs/en_US/images/debug_params.png and b/docs/en_US/images/debug_params.png differ
diff --git a/web/pgadmin/static/js/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid.pgadmin.js
index 4ce46d0bf..bb249268e 100644
--- a/web/pgadmin/static/js/backgrid.pgadmin.js
+++ b/web/pgadmin/static/js/backgrid.pgadmin.js
@@ -1916,6 +1916,58 @@ define([
},
});
+ Backgrid.BooleanCell = Backgrid.BooleanCell.extend({
+ className: 'boolean-cell',
+
+ enterEditMode: function() {
+ this.$el.addClass('editor');
+ $(this.$el.find('input[type=checkbox]')).trigger('focus');
+ },
+
+ exitEditMode: function() {
+ this.$el.removeClass('editor');
+ },
+
+ events: {
+ 'change input': 'onChange',
+ 'blur input': 'exitEditMode',
+ 'keydown': 'onKeyDown',
+ },
+
+ onChange: function(e) {
+ var model = this.model,
+ column = this.column,
+ val = this.formatter.toRaw(this.$input.prop('checked'), model);
+
+ this.enterEditMode();
+ // on bootstrap change we also need to change model's value
+ model.set(column.get('name'), val);
+ model.trigger('backgrid:edited', model, column, new Backgrid.Command(e));
+ },
+
+ render: function () {
+ this.$el.empty();
+ var model = this.model, column = this.column;
+ var editable = Backgrid.callByNeed(column.editable(), column, model);
+ var align_center = column.get('align_center') || false;
+ let checked = this.formatter.fromRaw(model.get(column.get('name')), model);
+ let id = `column.get('name')_${_.uniqueId()}`;
+
+ this.$el.empty();
+ this.$el.append(
+ $(`
+
+
+
`)
+ );
+ this.$input = this.$el.find('input');
+ this.delegateEvents();
+ return this;
+ },
+ });
+
return Backgrid;
});
diff --git a/web/pgadmin/tools/debugger/__init__.py b/web/pgadmin/tools/debugger/__init__.py
index e75e2eb70..2336d538d 100644
--- a/web/pgadmin/tools/debugger/__init__.py
+++ b/web/pgadmin/tools/debugger/__init__.py
@@ -241,7 +241,7 @@ class DebuggerModule(PgAdminModule):
'debugger.start_execution', 'debugger.set_breakpoint',
'debugger.clear_all_breakpoint', 'debugger.deposit_value',
'debugger.select_frame', 'debugger.get_arguments',
- 'debugger.set_arguments',
+ 'debugger.set_arguments', 'debugger.clear_arguments',
'debugger.poll_end_execution_result', 'debugger.poll_result'
]
@@ -1797,9 +1797,10 @@ def set_arguments_sqlite(sid, did, scid, func_id):
db.session.add(debugger_func_args)
- db.session.commit()
+ db.session.commit()
except Exception as e:
+ db.session.rollback()
current_app.logger.exception(e)
return make_json_response(
status=410,
@@ -1810,6 +1811,51 @@ def set_arguments_sqlite(sid, did, scid, func_id):
return make_json_response(data={'status': True, 'result': 'Success'})
+@blueprint.route(
+ '/clear_arguments////',
+ methods=['POST'], endpoint='clear_arguments'
+)
+@login_required
+def clear_arguments_sqlite(sid, did, scid, func_id):
+ """
+ clear_arguments_sqlite(sid, did, scid, func_id)
+
+ This method is responsible for clearing function arguments
+ from sqlite database
+
+ Parameters:
+ sid
+ - Server Id
+ did
+ - Database Id
+ scid
+ - Schema Id
+ func_id
+ - Function Id
+ """
+
+ try:
+ db.session.query(DebuggerFunctionArguments) \
+ .filter(DebuggerFunctionArguments.server_id == sid,
+ DebuggerFunctionArguments.database_id == did,
+ DebuggerFunctionArguments.schema_id == scid,
+ DebuggerFunctionArguments.function_id == func_id) \
+ .delete()
+
+ db.session.commit()
+
+ except Exception as e:
+ db.session.rollback()
+ current_app.logger.exception(e)
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=str(e)
+ )
+
+ return make_json_response(data={'status': True, 'result': 'Success'})
+
+
def convert_data_to_dict(conn, result):
"""
This function helps us to convert result set into dict
diff --git a/web/pgadmin/tools/debugger/static/js/debugger_ui.js b/web/pgadmin/tools/debugger/static/js/debugger_ui.js
index cab459476..0e70a386a 100644
--- a/web/pgadmin/tools/debugger/static/js/debugger_ui.js
+++ b/web/pgadmin/tools/debugger/static/js/debugger_ui.js
@@ -69,7 +69,7 @@ define([
// 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')),
+ 'value': isNaN(parseInt(model.get('value'))) ? null : parseInt(model.get('value')),
}, {
silent: true,
});
@@ -289,6 +289,7 @@ define([
label: gettext('Null?'),
type: 'boolean',
cell: 'boolean',
+ align_center: true,
},
{
name: 'expr',
@@ -296,6 +297,7 @@ define([
type: 'boolean',
cellFunction: cellExprControlFunction,
editable: disableExpressionControl,
+ align_center: true,
},
{
name: 'value',
@@ -304,6 +306,7 @@ define([
editable: true,
cellFunction: cellFunction,
headerCell: value_header,
+ align_center: true,
},
{
name: 'use_default',
@@ -413,12 +416,12 @@ define([
// Need to update the func_obj variable from sqlite database if available
if (func_args_data.length != 0) {
for (i = 0; i < func_args_data.length; i++) {
+ index = func_args_data[i]['arg_id'];
if (debug_info['proargmodes'] != null &&
- (argmode[i] == 'o' && !is_edb_proc)) {
+ (argmode[index] == 'o' && !is_edb_proc)) {
continue;
}
- index = func_args_data[i]['arg_id'];
values = [];
if (argtype[index].indexOf('[]') != -1) {
vals = func_args_data[i]['value'].split(',');
@@ -565,14 +568,17 @@ define([
});
grid.render();
- $(this.elements.content).html(grid.el);
+ let wrap_div = document.createElement('div');
+ wrap_div.classList.add('debugger-args');
+ wrap_div.appendChild(grid.el);
+ $(this.elements.content).html(wrap_div);
// For keyboard navigation in the grid
// we'll set focus on checkbox from the first row if any
var grid_checkbox = $(grid.el).find('input:checkbox').first();
if (grid_checkbox.length) {
setTimeout(function() {
- grid_checkbox.trigger('click');
+ grid_checkbox.trigger('focus');
}, 250);
}
@@ -585,6 +591,9 @@ define([
setup: function() {
return {
buttons: [{
+ text: gettext('Clear All'),
+ className: 'btn btn-secondary pull-left fa fa-eraser pg-alertify-button',
+ },{
text: gettext('Cancel'),
key: 27,
className: 'btn btn-secondary fa fa-times pg-alertify-button',
@@ -899,6 +908,65 @@ define([
return false;
}
+
+ if (e.button.text === gettext('Clear All')) {
+ let self = this;
+ let baseUrl = null;
+
+ if (self.setting('restart_debug') == 0) {
+ let selected_item = pgBrowser.tree.selected();
+ let item_data = pgBrowser.tree.itemData(selected_item);
+ if (!item_data)
+ return;
+
+ let node = pgBrowser.Nodes[item_data._type];
+ let treeInfo = node.getTreeNodeHierarchy.call(node, selected_item);
+
+ let f_id;
+ if (item_data._type == 'function') {
+ f_id = item_data._id;
+ } else if (item_data._type == 'procedure') {
+ f_id = item_data._id;
+ } else if (item_data._type == 'edbfunc') {
+ f_id = item_data._id;
+ } else if (item_data._type == 'edbproc') {
+ f_id = item_data._id;
+ }
+
+ baseUrl = url_for('debugger.clear_arguments', {
+ 'sid': treeInfo.server._id,
+ 'did': treeInfo.database._id,
+ 'scid': treeInfo.schema._id,
+ 'func_id': f_id,
+ });
+ } else {
+ baseUrl = url_for('debugger.clear_arguments', {
+ 'sid': self.setting('debug_info').server_id,
+ 'did': self.setting('debug_info').database_id,
+ 'scid': self.setting('debug_info').schema_id,
+ 'func_id': self.setting('debug_info').function_id,
+ });
+ }
+ $.ajax({
+ url: baseUrl,
+ method: 'POST',
+ data: {
+ 'data': JSON.stringify(args_value_list),
+ },
+ }).done(function() {
+ /* Disable debug button */
+ self.__internal.buttons[2].element.disabled = true;
+ self.main(self.setting('title'), debug_info, restart_debug, is_edb_proc, trans_id);
+ }).fail(function(e) {
+ Alertify.alert(
+ gettext('Clear failed'),
+ e.responseJSON.errormsg
+ );
+ });
+
+ e.cancel = true;
+ return true;
+ }
},
build: function() {
Alertify.pgDialogBuild.apply(this);
@@ -914,9 +982,9 @@ define([
enable the debug button otherwise disable the debug button.
*/
if (this.func_args_data.length == 0) {
- this.__internal.buttons[1].element.disabled = true;
+ this.__internal.buttons[2].element.disabled = true;
} else {
- this.__internal.buttons[1].element.disabled = false;
+ this.__internal.buttons[2].element.disabled = false;
}
/*
@@ -933,7 +1001,7 @@ define([
for (var i = 0; i < this.collection.length; i++) {
if (this.collection.models[i].get('is_null')) {
- obj.__internal.buttons[1].element.disabled = false;
+ obj.__internal.buttons[2].element.disabled = false;
enable_btn = true;
continue;
}
@@ -944,15 +1012,15 @@ define([
enable_btn = true;
if (this.collection.models[i].get('use_default')) {
- obj.__internal.buttons[1].element.disabled = false;
+ obj.__internal.buttons[2].element.disabled = false;
} else {
- obj.__internal.buttons[1].element.disabled = true;
+ obj.__internal.buttons[2].element.disabled = true;
break;
}
}
}
if (!enable_btn)
- obj.__internal.buttons[1].element.disabled = false;
+ obj.__internal.buttons[2].element.disabled = false;
};
})(this)
);
@@ -960,7 +1028,7 @@ define([
this.grid.listenTo(this.debuggerInputArgsColl, 'backgrid:error',
(function(obj) {
return function() {
- obj.__internal.buttons[1].element.disabled = true;
+ obj.__internal.buttons[2].element.disabled = true;
};
})(this)
);
diff --git a/web/pgadmin/tools/debugger/static/scss/_debugger.scss b/web/pgadmin/tools/debugger/static/scss/_debugger.scss
index 4fa35195f..30ace0af7 100644
--- a/web/pgadmin/tools/debugger/static/scss/_debugger.scss
+++ b/web/pgadmin/tools/debugger/static/scss/_debugger.scss
@@ -16,3 +16,10 @@
-ms-user-select: text;
user-select: text;
}
+
+.debugger-args {
+ display: block;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+}