From d6391c7e9b26e5e10bb38a4d90f4503a4cb3e63f Mon Sep 17 00:00:00 2001 From: Murtuza Zabuawala Date: Thu, 18 Aug 2016 17:08:40 +0100 Subject: [PATCH] Properly display messages from the server in the query tool. Fixes #1523 --- web/pgadmin/tools/sqleditor/__init__.py | 37 ++++++---- .../tools/sqleditor/static/css/sqleditor.css | 3 + .../templates/sqleditor/js/sqleditor.js | 67 ++++++++++++------- web/pgadmin/utils/driver/psycopg2/__init__.py | 38 ++++------- 4 files changed, 82 insertions(+), 63 deletions(-) diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py index bb5c26bae..6de42b01b 100644 --- a/web/pgadmin/tools/sqleditor/__init__.py +++ b/web/pgadmin/tools/sqleditor/__init__.py @@ -406,8 +406,10 @@ def poll(trans_id): trans_id: unique transaction id """ col_info = None + result = None primary_keys = None rows_affected = 0 + additional_result = [] # Check the transaction and connection status status, error_msg, conn, trans_obj, session_obj = check_transaction_status(trans_id) @@ -430,6 +432,10 @@ def poll(trans_id): status = 'Cancel' else: status = 'Busy' + messages = conn.messages() + if messages and len(messages) > 0: + result = ''.join(messages) + else: status = 'NotConnected' result = error_msg @@ -450,20 +456,25 @@ def poll(trans_id): # restore it and update the session variable. session_obj['columns_info'] = columns update_session_grid_transaction(trans_id, session_obj) - else: - if result is None: - result = conn.status_message() - additional_result = conn.messages() - """ - Procedure/Function output may comes in the form of Notices from the - database server, so we need to append those outputs with the - original result. - """ - if isinstance(additional_result, list) \ - and len(additional_result) > 0: - result = "{0} {1}".format(additional_result[-1], result) - rows_affected = conn.rows_affected() + """ + Procedure/Function output may comes in the form of Notices from the + database server, so we need to append those outputs with the + original result. + """ + if status == 'Success' and result is None: + result = conn.status_message() + messages = conn.messages() + if messages: + additional_result = ''.join(messages) + else: + additional_result = '' + if result != 'SELECT 1' and result is not None: + result = additional_result + result + else: + result = additional_result + + rows_affected = conn.rows_affected() return make_json_response( data={ diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index 93c792147..84fbf1c21 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -160,6 +160,9 @@ font-family: monospace; padding-top: 5px; padding-left: 10px; + overflow: auto; + height: 100%; + font-size: 0.925em; } .limit-enabled { diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index 22335868a..7a66cf913 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -1291,7 +1291,13 @@ define( else { // Show message in message and history tab in case of query tool self.total_time = self.get_query_run_time(self.query_start_time, self.query_end_time); - self.update_msg_history(true, res.data.result); + var msg = S('{{ _('Query returned successfully in %s.') }}').sprintf(self.total_time).value(); + res.data.result += "\n\n" + msg; + self.update_msg_history(true, res.data.result, false); + // Display the notifier if the timeout is set to >= 0 + if (self.info_notifier_timeout >= 0) { + alertify.success(msg, self.info_notifier_timeout); + } } // Enable/Disable query tool button only if is_query_tool is true. @@ -1305,6 +1311,9 @@ define( // If status is Busy then poll the result by recursive call to the poll function self._poll(); is_query_running = true; + if (res.data.result) { + self.update_msg_history(res.data.status, res.data.result, false); + } } else if (res.data.status === 'NotConnected') { @@ -1313,10 +1322,10 @@ define( self.disable_tool_buttons(false); $("#btn-cancel-query").prop('disabled', true); } - self.update_msg_history(false, res.data.result); + self.update_msg_history(false, res.data.result, true); } else if (res.data.status === 'Cancel') { - self.update_msg_history(false, "Execution Cancelled!") + self.update_msg_history(false, "Execution Cancelled!", true) } }, error: function(e) { @@ -1687,35 +1696,43 @@ define( // This function is used to raise appropriate message. update_msg_history: function(status, msg, clear_grid) { var self = this; - if (clear_grid === undefined) clear_grid = true; - self.trigger('pgadmin-sqleditor:loading-icon:hide'); - $("#btn-flash").prop('disabled', false); - - $('.sql-editor-message').text(msg); self.gridView.messages_panel.focus(); - if (self.is_query_tool && clear_grid) { - // Delete grid and paginator - if (self.gridView.grid) { - self.gridView.grid.remove(); + if (self.is_query_tool) { + if (clear_grid) { + // Delete grid and paginator + if (self.gridView.grid) { + self.gridView.grid.remove(); + } + // Misc cleaning self.columns = undefined; self.collection = undefined; + + if (self.gridView.paginator) + self.gridView.paginator.remove(); + $('.sql-editor-message').text(msg); + } else { + $('.sql-editor-message').append(msg); } - - if (self.gridView.paginator) - self.gridView.paginator.remove(); } + // Scroll automatically when msgs appends to element + setTimeout(function(){ + $(".sql-editor-message").scrollTop($(".sql-editor-message")[0].scrollHeight);; + }, 10); - self.gridView.history_collection.add( - {'status' : status, 'start_time': self.query_start_time.toString(), - 'query': self.query, 'row_affected': self.rows_affected, - 'total_time': self.total_time, 'message':msg - }); - - self.gridView.history_collection.sort(); + if(status != 'Busy') { + $("#btn-flash").prop('disabled', false); + self.trigger('pgadmin-sqleditor:loading-icon:hide'); + self.gridView.history_collection.add({ + 'status' : status, 'start_time': self.query_start_time.toString(), + 'query': self.query, 'row_affected': self.rows_affected, + 'total_time': self.total_time, 'message':msg + }); + self.gridView.history_collection.sort(); + } }, // This function will return the total query execution Time. @@ -2140,10 +2157,12 @@ define( var self = this; // Start execution of the query. - if (self.is_query_tool) + if (self.is_query_tool) { + $('.sql-editor-message').html(''); self._execute(); - else + } else { self._execute_data_query(); + } }, // This function will show the filter in the text area. diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py index fbde603dc..05622e607 100644 --- a/web/pgadmin/utils/driver/psycopg2/__init__.py +++ b/web/pgadmin/utils/driver/psycopg2/__init__.py @@ -178,6 +178,7 @@ class Connection(BaseConnection): self.__backend_pid = None self.execution_aborted = False self.row_count = 0 + self.__notices = None super(Connection, self).__init__() @@ -639,6 +640,7 @@ Attempt to reconnect it failed with the error: ) try: + self.__notices = [] self.execution_aborted = False cur.execute(query, params) res = self._wait_timeout(cur.connection, ASYNC_WAIT_TIMEOUT) @@ -904,31 +906,9 @@ Failed to reset the connection to the server due to following error: if state == psycopg2.extensions.POLL_OK: return self.ASYNC_OK elif state == psycopg2.extensions.POLL_WRITE: - # Wait for the given time and then check the return status - # If three empty lists are returned then the time-out is reached. - timeout_status = select.select([], [conn.fileno()], [], time) - if timeout_status == ([], [], []): - return self.ASYNC_WRITE_TIMEOUT - - # poll again to check the state if it is still POLL_WRITE - # then return ASYNC_WRITE_TIMEOUT else return ASYNC_OK. - state = conn.poll() - if state == psycopg2.extensions.POLL_WRITE: - return self.ASYNC_WRITE_TIMEOUT - return self.ASYNC_OK + return self.ASYNC_WRITE_TIMEOUT elif state == psycopg2.extensions.POLL_READ: - # Wait for the given time and then check the return status - # If three empty lists are returned then the time-out is reached. - timeout_status = select.select([conn.fileno()], [], [], time) - if timeout_status == ([], [], []): - return self.ASYNC_READ_TIMEOUT - - # poll again to check the state if it is still POLL_READ - # then return ASYNC_READ_TIMEOUT else return ASYNC_OK. - state = conn.poll() - if state == psycopg2.extensions.POLL_READ: - return self.ASYNC_READ_TIMEOUT - return self.ASYNC_OK + return self.ASYNC_READ_TIMEOUT else: raise psycopg2.OperationalError( "poll() returned %s from _wait_timeout function" % state @@ -965,6 +945,10 @@ Failed to reset the connection to the server due to following error: errmsg = self._formatted_exception_msg(pe, formatted_exception_msg) return False, errmsg, None + if self.conn.notices and self.__notices is not None: + while self.conn.notices: + self.__notices.append(self.conn.notices.pop(0)[:]) + colinfo = None result = None self.row_count = 0 @@ -996,7 +980,6 @@ Failed to reset the connection to the server due to following error: result.append(dict(row)) except psycopg2.ProgrammingError: result = None - return status, result, colinfo def status_message(self): @@ -1094,7 +1077,10 @@ Failed to reset the connection to the server due to following error: """ Returns the list of the messages/notices send from the database server. """ - return self.conn.notices if self.conn else [] + resp = [] + while self.__notices: + resp.append(self.__notices.pop(0)) + return resp def _formatted_exception_msg(self, exception_obj, formatted_msg): """