diff --git a/web/pgadmin/static/js/api_instance.js b/web/pgadmin/static/js/api_instance.js index b1074f80f..8c01723df 100644 --- a/web/pgadmin/static/js/api_instance.js +++ b/web/pgadmin/static/js/api_instance.js @@ -23,12 +23,16 @@ export default function getApiInstance(headers={}) { }); } -export function parseApiError(error) { +export function parseApiError(error, withData=false) { if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx if(error.response.headers['content-type'] == 'application/json') { - return error.response.data.errormsg; + let errormsg = error.response.data.errormsg; + let data = error.response.data.data; + // If we want to use data which came with error set withData + // flag to true. + return withData ? {errormsg, data} : errormsg; } else { return error.response.statusText; } diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py index 10e1e813e..acf6f54a8 100644 --- a/web/pgadmin/tools/sqleditor/__init__.py +++ b/web/pgadmin/tools/sqleditor/__init__.py @@ -57,6 +57,8 @@ from pgadmin.model import Server, ServerGroup from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry from pgadmin.settings import get_setting from pgadmin.utils.preferences import Preferences +from pgadmin.tools.sqleditor.utils.apply_explain_plan_wrapper import \ + get_explain_query_length MODULE_NAME = 'sqleditor' TRANSACTION_STATUS_CHECK_FAILED = gettext("Transaction status check failed.") @@ -956,7 +958,12 @@ def poll(trans_id): gettext('******* Error *******'), result ) - return internal_server_error(result) + query_len_data = { + 'explain_query_length': + get_explain_query_length( + conn._Connection__async_cursor._query) + } + return internal_server_error(result, query_len_data) elif status == ASYNC_OK: status = 'Success' rows_affected = conn.rows_affected() diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx index db3a5be7a..d01defc0e 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/Query.jsx @@ -253,17 +253,20 @@ export default function Query() { cmObj.removeLineClass(markedLine.current, 'wrap', 'CodeMirror-activeline-background'); markedLine.current = 0; }; - const highlightError = (cmObj, result)=>{ + const highlightError = (cmObj, {errormsg: result, data})=>{ let errorLineNo = 0, startMarker = 0, endMarker = 0, - selectedLineNo = 0; + selectedLineNo = 0, + origQueryLen = cmObj.getValue().length; removeHighlightError(cmObj); // In case of selection we need to find the actual line no - if (cmObj.getSelection().length > 0) + if (cmObj.getSelection().length > 0) { selectedLineNo = cmObj.getCursor(true).line; + origQueryLen = cmObj.getLine(selectedLineNo).length; + } // Fetch the LINE string using regex from the result let line = /LINE (\d+)/.exec(result), @@ -275,6 +278,14 @@ export default function Query() { errorLineNo = (parseInt(line[1]) - 1) + selectedLineNo; let errorCharNo = (parseInt(char[1]) - 1); + /* If explain query has been run we need to + calculate the character number. + */ + if(data.explain_query_length) { + let explainQueryLen = data.explain_query_length - parseInt(char[1]); + errorCharNo = origQueryLen - explainQueryLen - 1; + } + /* We need to loop through each line till the error line and * count the total no of character to figure out the actual * starting/ending marker point for the individual line. We @@ -312,7 +323,7 @@ export default function Query() { markedLine.current = errorLineNo; cmObj.addLineClass(errorLineNo, 'wrap', 'CodeMirror-activeline-background'); cmObj.focus(); - cmObj.setCursor(errorLineNo, 0); + cmObj.setCursor(errorLineNo, endMarker); } }; diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx index d86fd6c19..533dad830 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx @@ -284,7 +284,7 @@ export class ResultSetUtils { this.eventBus.fireEvent(QUERY_TOOL_EVENTS.FOCUS_PANEL, PANELS.MESSAGES); this.eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_CONNECTION_STATUS, CONNECTION_STATUS.TRANSACTION_STATUS_INERROR); if (!flags.external) { - this.eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, parseApiError(error)); + this.eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, parseApiError(error, true)); } this.eventBus.fireEvent(QUERY_TOOL_EVENTS.PUSH_HISTORY, { status: false, diff --git a/web/pgadmin/tools/sqleditor/utils/apply_explain_plan_wrapper.py b/web/pgadmin/tools/sqleditor/utils/apply_explain_plan_wrapper.py index c8c3cc44f..026523646 100644 --- a/web/pgadmin/tools/sqleditor/utils/apply_explain_plan_wrapper.py +++ b/web/pgadmin/tools/sqleditor/utils/apply_explain_plan_wrapper.py @@ -25,3 +25,17 @@ def apply_explain_plan_wrapper_if_needed(manager, sql): return render_template(template_path, sql=sql['sql'], **explain_plan) else: return sql['sql'] + + +def get_explain_query_length(query_obj): + """ + This method returns query length if it is explain query. + + Args: + query_obj: sql query + """ + query = query_obj.query.decode() + if query.startswith("EXPLAIN"): + return len(query) + else: + return 0 diff --git a/web/pgadmin/utils/ajax.py b/web/pgadmin/utils/ajax.py index f298bf0df..12d52789d 100644 --- a/web/pgadmin/utils/ajax.py +++ b/web/pgadmin/utils/ajax.py @@ -95,12 +95,13 @@ def make_response(response=None, status=200): ) -def internal_server_error(errormsg=''): +def internal_server_error(errormsg='',data=None): """Create a response with HTTP status code 500 - Internal Server Error.""" return make_json_response( status=500, success=0, - errormsg=errormsg + errormsg=errormsg, + data=data )