Fix an initialisation error when two functions with parameters are debugged in parallel. Fixes #4329

This commit is contained in:
Aditya Toshniwal 2019-06-10 14:58:07 +01:00 committed by Dave Page
parent 6d52f2b911
commit 5437a8adab
6 changed files with 387 additions and 371 deletions

View File

@ -22,4 +22,5 @@ Bug fixes
| `Bug #4255 <https://redmine.postgresql.org/issues/4255>`_ - Prevent the geometry viewer grabbing key presses when not in focus under Firefox, IE and Edge.
| `Bug #4310 <https://redmine.postgresql.org/issues/4310>`_ - Ensure that the Return key can be used to submit the Master Password dialogue.
| `Bug #4317 <https://redmine.postgresql.org/issues/4317>`_ - Ensure that browser auto-fill doesn't cause Help pages to be opened unexpectedly.
| `Bug #4320 <https://redmine.postgresql.org/issues/4320>`_ - Fix issue where SSH tunnel connection using password is failing, it's regression of Master Password.
| `Bug #4320 <https://redmine.postgresql.org/issues/4320>`_ - Fix issue where SSH tunnel connection using password is failing, it's regression of Master Password.
| `Bug #4329 <https://redmine.postgresql.org/issues/4329>`_ - Fix an initialisation error when two functions with parameters are debugged in parallel.

File diff suppressed because it is too large Load Diff

View File

@ -313,8 +313,8 @@ define([
url: _url,
cache: false,
})
.done(function() {
self.start_global_debugger();
.done(function(res) {
self.start_global_debugger(args, item, res.data.trans_id);
})
.fail(function(xhr) {
try {
@ -329,7 +329,7 @@ define([
},
//Callback function when user start the indirect debugging ( Listen to another session to invoke the target )
start_global_debugger: function(args, item) {
start_global_debugger: function(args, item, trans_id) {
// Initialize the target and create asynchronous connection and unique transaction ID
var t = pgBrowser.tree,
i = item || t.selected(),
@ -343,48 +343,33 @@ define([
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]),
baseUrl;
if (d._type == 'function') {
if (d._type == 'function' || d._type == 'edbfunc') {
baseUrl = url_for(
'debugger.initialize_target_for_function', {
'debug_type': 'indirect',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
'func_id': treeInfo.function._id,
'func_id': debuggerUtils.getFunctionId(treeInfo),
}
);
} else if (d._type == 'procedure') {
} else if (d._type == 'procedure' || d._type == 'edbproc') {
baseUrl = url_for(
'debugger.initialize_target_for_function', {
'debug_type': 'indirect',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
'func_id': debuggerUtils.getProcedureId(treeInfo),
}
);
} else if (d._type == 'edbfunc') {
// Get the existing function parameters available from sqlite database
baseUrl = url_for('debugger.initialize_target_for_function', {
'debug_type': 'indirect',
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
'func_id': treeInfo.edbfunc._id,
});
} else if (d._type == 'edbproc') {
// Get the existing function parameters available from sqlite database
baseUrl = url_for('debugger.initialize_target_for_function', {
'debug_type': 'indirect',
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
'func_id': treeInfo.edbproc._id,
});
} else if (d._type == 'trigger_function') {
baseUrl = url_for(
'debugger.initialize_target_for_function', {
'debug_type': 'indirect',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -395,6 +380,7 @@ define([
baseUrl = url_for(
'debugger.initialize_target_for_trigger', {
'debug_type': 'indirect',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -406,6 +392,7 @@ define([
baseUrl = url_for(
'debugger.initialize_target_for_trigger', {
'debug_type': 'indirect',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -491,9 +478,11 @@ define([
})
.done(function(res) {
let debug_info = res.data.debug_info,
trans_id = res.data.trans_id;
// 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, is_edb_proc);
if (debug_info[0]['require_input']) {
get_function_arguments(debug_info[0], 0, is_edb_proc, trans_id);
} 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
@ -509,20 +498,22 @@ define([
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]),
baseUrl;
if (d._type == 'function') {
if (d._type == 'function' || d._type == 'edbfunc') {
baseUrl = url_for(
'debugger.initialize_target_for_function', {
'debug_type': 'direct',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
'func_id': treeInfo.function._id,
'func_id': debuggerUtils.getFunctionId(treeInfo),
}
);
} else {
} else if(d._type == 'procedure' || d._type == 'edbproc') {
baseUrl = url_for(
'debugger.initialize_target_for_function', {
'debug_type': 'direct',
'trans_id': trans_id,
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -535,10 +526,10 @@ define([
url: baseUrl,
method: 'GET',
})
.done(function(res) {
.done(function() {
var url = url_for('debugger.direct', {
'trans_id': res.data.debuggerTransId,
'trans_id': trans_id,
});
if (self.preferences.debugger_new_browser_tab) {
@ -563,7 +554,7 @@ define([
// Register Panel Closed event
panel.on(wcDocker.EVENT.CLOSED, function() {
var closeUrl = url_for('debugger.close', {
'trans_id': res.data.debuggerTransId,
'trans_id': trans_id,
});
$.ajax({
url: closeUrl,

View File

@ -163,11 +163,11 @@ define([
}
};
var res = function(debug_info, restart_debug, is_edb_proc) {
var res = function(debug_info, restart_debug, is_edb_proc, trans_id) {
if (!Alertify.debuggerInputArgsDialog) {
Alertify.dialog('debuggerInputArgsDialog', function factory() {
return {
main: function(title, debug_info, restart_debug, is_edb_proc) {
main: function(title, debug_info, restart_debug, is_edb_proc, trans_id) {
this.preferences = window.top.pgAdmin.Browser.get_preferences_for_module('debugger');
this.set('title', title);
@ -175,6 +175,7 @@ define([
// other functions other than main function.
this.set('debug_info', debug_info);
this.set('restart_debug', restart_debug);
this.set('trans_id', trans_id);
// Variables to store the data sent from sqlite database
var func_args_data = this.func_args_data = [];
@ -579,6 +580,7 @@ define([
settings: {
debug_info: undefined,
restart_debug: undefined,
trans_id: undefined,
},
setup: function() {
return {
@ -706,6 +708,7 @@ define([
if (d._type == 'function') {
baseUrl = url_for('debugger.initialize_target_for_function', {
'debug_type': 'direct',
'trans_id': self.setting('trans_id'),
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -714,6 +717,7 @@ define([
} else if (d._type == 'procedure') {
baseUrl = url_for('debugger.initialize_target_for_function', {
'debug_type': 'direct',
'trans_id': self.setting('trans_id'),
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -722,6 +726,7 @@ define([
} else if (d._type == 'edbfunc') {
baseUrl = url_for('debugger.initialize_target_for_function', {
'debug_type': 'direct',
'trans_id': self.setting('trans_id'),
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -730,6 +735,7 @@ define([
} else if (d._type == 'edbproc') {
baseUrl = url_for('debugger.initialize_target_for_function', {
'debug_type': 'direct',
'trans_id': self.setting('trans_id'),
'sid': treeInfo.server._id,
'did': treeInfo.database._id,
'scid': treeInfo.schema._id,
@ -885,7 +891,12 @@ define([
}
if (e.button.text === gettext('Cancel')) {
//close the dialog...
/* Clear the trans id */
$.ajax({
method: 'DELETE',
url: url_for('debugger.close', {'trans_id': this.setting('trans_id')}),
});
return false;
}
},
@ -959,7 +970,7 @@ define([
}
Alertify.debuggerInputArgsDialog(
gettext('Debugger'), debug_info, restart_debug, is_edb_proc
gettext('Debugger'), debug_info, restart_debug, is_edb_proc, trans_id
).resizeTo(pgBrowser.stdW.md,pgBrowser.stdH.md);
};

View File

@ -18,6 +18,18 @@ function setFocusToDebuggerEditor(editor, command) {
}
}
function getFunctionId(treeInfoObject) {
let objectId;
if(treeInfoObject) {
if (treeInfoObject.function && treeInfoObject.function._id) {
objectId = treeInfoObject.function._id;
} else if (treeInfoObject.edbfunc && treeInfoObject.edbfunc._id) {
objectId = treeInfoObject.edbfunc._id;
}
}
return objectId;
}
function getProcedureId(treeInfoObject) {
let objectId;
if(treeInfoObject) {
@ -32,5 +44,6 @@ function getProcedureId(treeInfoObject) {
module.exports = {
setFocusToDebuggerEditor: setFocusToDebuggerEditor,
getFunctionId: getFunctionId,
getProcedureId: getProcedureId,
};

View File

@ -0,0 +1,81 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from flask import session
from threading import Lock
import random
debugger_sessions_lock = Lock()
class DebuggerInstance:
def __init__(self, trans_id=None):
if trans_id is None:
self._trans_id = str(random.randint(1, 9999999))
else:
self._trans_id = trans_id
self._function_data = None
self._debugger_data = None
self.load_from_session()
@property
def trans_id(self):
"""
trans_id be readonly with no setter
"""
return self._trans_id
@property
def function_data(self):
return self._function_data
@function_data.setter
def function_data(self, data):
self._function_data = data
self.update_session()
@property
def debugger_data(self):
return self._debugger_data
@debugger_data.setter
def debugger_data(self, data):
self._debugger_data = data
self.update_session()
@staticmethod
def get_trans_ids():
if '__debugger_sessions' in session:
return [trans_id for trans_id in session['__debugger_sessions']]
else:
return []
def load_from_session(self):
if '__debugger_sessions' in session:
if str(self.trans_id) in session['__debugger_sessions']:
trans_data = session['__debugger_sessions'][str(self.trans_id)]
self.function_data = trans_data.get('function_data', None)
self.debugger_data = trans_data.get('debugger_data', None)
def update_session(self):
with debugger_sessions_lock:
if '__debugger_sessions' not in session:
session['__debugger_sessions'] = dict()
session['__debugger_sessions'][str(self.trans_id)] = dict(
function_data=self.function_data,
debugger_data=self.debugger_data
)
def clear(self):
with debugger_sessions_lock:
if '__debugger_sessions' in session:
if str(self.trans_id) in session['__debugger_sessions']:
session['__debugger_sessions'].pop(str(self.trans_id))