diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py index db938bc..eb8ac94 100644 --- a/web/pgadmin/utils/driver/psycopg2/__init__.py +++ b/web/pgadmin/utils/driver/psycopg2/__init__.py @@ -35,7 +35,7 @@ from .keywords import ScanKeyword _ = gettext -ASYNC_WAIT_TIMEOUT = 0.1 # in seconds or 100 milliseconds +ASYNC_WAIT_TIMEOUT = 0.01 # in seconds or 10 milliseconds class Connection(BaseConnection): @@ -102,6 +102,11 @@ class Connection(BaseConnection): * messages() - Returns the list of messages/notices sends from the PostgreSQL database server. + + * _formatted_error_msg(err_obj) + - This method is used to parse the psycopg2.Error object and returns the + formatted error message. + """ def __init__(self, manager, conn_id, db, auto_reconnect=True, async=0): assert(manager is not None) @@ -447,15 +452,17 @@ Attempt to reconnect it failed with the below error: return True, None - def execute_async(self, query, params=None): + def execute_async(self, query, params=None, formatted_error=False): """ This function executes the given query asynchronously and returns result. Args: query: SQL query to run. params: extra parameters to the function + formatted_error: if True then function return the formatted error """ status, cur = self.__cursor() + self.formatted_error = formatted_error if not status: return False, str(cur) @@ -475,7 +482,17 @@ Execute (async) for server #{server_id} - {conn_id} (Query-id: {query_id}):\n{qu cur.execute(query, params) res = self._wait_timeout(cur.connection, ASYNC_WAIT_TIMEOUT) except psycopg2.Error as pe: - errmsg = str(pe) + if self.formatted_error: + # Get the formatted error message + errmsg = self._formatted_error_msg(pe) + else: + if pe.pgerror: + errmsg = pe.pgerror + elif pe.diag.message_detail: + errmsg = pe.diag.message_detail + else: + errmsg = str(pe) + current_app.logger.error(""" Failed to execute query (execute_async) for the server #{server_id} - {conn_id} (Query-id: {query_id}):\nError Message:{errmsg} @@ -728,11 +745,15 @@ Failed to reset the connection of the server due to following error: if state == psycopg2.extensions.POLL_OK: return self.ASYNC_OK elif state == psycopg2.extensions.POLL_WRITE: - select.select([], [conn.fileno()], [], time) - return self.ASYNC_WRITE_TIMEOUT + if select.select([], [conn.fileno()], [], time) == ([], [], []): + return self.ASYNC_WRITE_TIMEOUT + # Call recursively if no timeout + self._wait_timeout(conn, time) elif state == psycopg2.extensions.POLL_READ: - select.select([conn.fileno()], [], [], time) - return self.ASYNC_READ_TIMEOUT + if select.select([conn.fileno()], [], [], time) == ([], [], []): + return self.ASYNC_READ_TIMEOUT + # Call recursively if no timeout + self._wait_timeout(conn, time) else: raise psycopg2.OperationalError("poll() returned %s from _wait_timeout function" % state) @@ -751,7 +772,21 @@ Failed to reset the connection of the server due to following error: current_app.logger.log(25, """ Polling result for (Query-id: {query_id})""".format(query_id=self.__async_query_id)) - status = self._wait_timeout(self.conn, ASYNC_WAIT_TIMEOUT) + try: + status = self._wait_timeout(self.conn, ASYNC_WAIT_TIMEOUT) + except psycopg2.Error as pe: + if self.formatted_error: + # Get the formatted error message + errmsg = self._formatted_error_msg(pe) + else: + if pe.pgerror: + errmsg = pe.pgerror + elif pe.diag.message_detail: + errmsg = pe.diag.message_detail + else: + errmsg = str(pe) + return False, errmsg, None + colinfo = None if status == self.ASYNC_OK: # Fetch the column information @@ -835,6 +870,64 @@ Polling result for (Query-id: {query_id})""".format(query_id=self.__async_query_ """ return self.conn.notices if self.conn else [] + def _formatted_error_msg(self, err_obj): + """ + This method is used to parse the psycopg2.Error object + and returns the formatted error message. + + Args: + err_obj: psycopg2.Error object + + Returns: Formatted error message + """ + + if err_obj.pgerror: + errmsg = err_obj.pgerror + elif err_obj.diag.message_detail: + errmsg = err_obj.diag.message_detail + else: + errmsg = str(err_obj) + + errmsg += '********** Error **********\n\n' + + if err_obj.diag.severity is not None \ + and err_obj.diag.message_primary is not None: + errmsg += err_obj.diag.severity + ": " + err_obj.diag.message_primary + elif err_obj.diag.message_primary is not None: + errmsg += err_obj.diag.message_primary + + if err_obj.diag.sqlstate is not None: + if not errmsg[:-1].endswith('\n'): + errmsg += '\n' + errmsg += gettext('SQL state: ') + errmsg += err_obj.diag.sqlstate + + if err_obj.diag.message_detail is not None: + if not errmsg[:-1].endswith('\n'): + errmsg += '\n' + errmsg += gettext('Detail: ') + errmsg += err_obj.diag.message_detail + + if err_obj.diag.message_hint is not None: + if not errmsg[:-1].endswith('\n'): + errmsg += '\n' + errmsg += gettext('Hint: ') + errmsg += err_obj.diag.message_hint + + if err_obj.diag.statement_position is not None: + if not errmsg[:-1].endswith('\n'): + errmsg += '\n' + errmsg += gettext('Character: ') + errmsg += err_obj.diag.statement_position + + if err_obj.diag.context is not None: + if not errmsg[:-1].endswith('\n'): + errmsg += '\n' + errmsg += gettext('Context: ') + errmsg += err_obj.diag.context + + return errmsg + class ServerManager(object): """