Files
pgadmin4/web/pgadmin/static/js/sqleditor/execute_query.js
T

368 lines
12 KiB
JavaScript
Raw Normal View History

2018-02-09 11:54:42 +00:00
//////////////////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
2021-01-04 15:34:45 +05:30
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
2018-02-09 11:54:42 +00:00
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////////////////
import gettext from '../gettext';
import $ from 'jquery';
import url_for from '../url_for';
import axios from 'axios';
import * as httpErrorHandler from './query_tool_http_error_handler';
import * as queryTxnStatus from 'sources/sqleditor/query_txn_status_constants';
import * as SqlEditorUtils from 'sources/sqleditor_utils';
2018-02-09 11:54:42 +00:00
class LoadingScreen {
constructor(sqlEditor) {
this.sqlEditor = sqlEditor;
}
setMessage(message) {
this.sqlEditor.trigger(
'pgadmin-sqleditor:loading-icon:message',
gettext(message)
);
}
show(withMessage) {
this.sqlEditor.trigger(
'pgadmin-sqleditor:loading-icon:show',
withMessage
);
}
hide() {
this.sqlEditor.trigger('pgadmin-sqleditor:loading-icon:hide');
}
}
class ExecuteQuery {
constructor(sqlEditor, userManagement) {
this.sqlServerObject = sqlEditor;
this.loadingScreen = new LoadingScreen(sqlEditor);
this.userManagement = userManagement;
}
delayedPoll() {
const self = this;
setTimeout(
() => {
self.poll();
}, self.sqlServerObject.POLL_FALLBACK_TIME());
}
execute(sqlStatement, explainPlan, connect) {
2018-02-09 11:54:42 +00:00
// If it is an empty query, do nothing.
if (sqlStatement.length <= 0) return;
const self = this;
self.explainPlan = explainPlan;
const sqlStatementWithAnalyze = ExecuteQuery.prepareAnalyzeSql(sqlStatement, explainPlan);
self.initializeExecutionOnSqlEditor(sqlStatementWithAnalyze);
axios.post(
this.generateURLReconnectionFlag(connect),
2018-02-09 11:54:42 +00:00
JSON.stringify(sqlStatementWithAnalyze),
{headers: {'Content-Type': 'application/json'}})
.then(function (result) {
let httpMessageData = result.data;
self.removeGridViewMarker();
self.updateSqlEditorLastTransactionStatus(httpMessageData.data.transaction_status);
2018-02-09 11:54:42 +00:00
if (ExecuteQuery.isSqlCorrect(httpMessageData)) {
2019-01-03 15:24:47 +00:00
self.loadingScreen.setMessage('Waiting for the query to complete...');
2018-02-09 11:54:42 +00:00
// Disable drop down arrow to change connections
SqlEditorUtils.disable_connection_dropdown(true);
2018-02-09 11:54:42 +00:00
self.updateSqlEditorStateWithInformationFromServer(httpMessageData.data);
// If status is True then poll the result.
self.delayedPoll();
} else {
self.loadingScreen.hide();
self.enableSQLEditorButtons();
self.disableDownloadButton();
// Enable/Disable commit and rollback button.
if (result.data.data.transaction_status == queryTxnStatus.TRANSACTION_STATUS_INTRANS
|| result.data.data.transaction_status == queryTxnStatus.TRANSACTION_STATUS_INERROR) {
self.enableTransactionButtons();
} else {
self.disableTransactionButtons();
}
2018-02-09 11:54:42 +00:00
self.sqlServerObject.update_msg_history(false, httpMessageData.data.result);
if ('notifies' in httpMessageData.data)
self.sqlServerObject.update_notifications(httpMessageData.data.notifies);
2018-02-09 11:54:42 +00:00
// Highlight the error in the sql panel
self.sqlServerObject._highlight_error(httpMessageData.data.result);
}
}).catch(function (error) {
self.onExecuteHTTPError(error);
2018-02-09 11:54:42 +00:00
}
);
2018-02-09 11:54:42 +00:00
}
generateURLReconnectionFlag(shouldReconnect) {
let url = url_for('sqleditor.query_tool_start', {
'trans_id': this.sqlServerObject.transId,
});
if (shouldReconnect) {
url += '?connect=1';
}
return url;
}
2018-02-09 11:54:42 +00:00
poll() {
const self = this;
axios.get(
2018-02-09 11:54:42 +00:00
url_for('sqleditor.poll', {
'trans_id': self.sqlServerObject.transId,
})
).then(
(httpMessage) => {
self.updateSqlEditorLastTransactionStatus(httpMessage.data.data.transaction_status);
// Enable/Disable commit and rollback button.
if (httpMessage.data.data.transaction_status == queryTxnStatus.TRANSACTION_STATUS_INTRANS
|| httpMessage.data.data.transaction_status == queryTxnStatus.TRANSACTION_STATUS_INERROR) {
self.enableTransactionButtons();
} else {
self.disableTransactionButtons();
}
2018-02-09 11:54:42 +00:00
if (ExecuteQuery.isQueryFinished(httpMessage)) {
if (this.sqlServerObject.close_on_idle_transaction &&
httpMessage.data.data.transaction_status == queryTxnStatus.TRANSACTION_STATUS_IDLE)
this.sqlServerObject.check_needed_confirmations_before_closing_panel();
2018-02-09 11:54:42 +00:00
self.loadingScreen.setMessage('Loading data from the database server and rendering...');
self.sqlServerObject.call_render_after_poll(httpMessage.data.data);
if ('notifies' in httpMessage.data.data)
self.sqlServerObject.update_notifications(httpMessage.data.data.notifies);
2018-02-09 11:54:42 +00:00
} else if (ExecuteQuery.isQueryStillRunning(httpMessage)) {
// If status is Busy then poll the result by recursive call to the poll function
this.delayedPoll();
self.sqlServerObject.setIsQueryRunning(true);
if (httpMessage.data.data.result) {
self.sqlServerObject.update_msg_history(httpMessage.data.data.status, httpMessage.data.data.result, false);
}
} else if (ExecuteQuery.isConnectionToServerLostWhilePolling(httpMessage)) {
self.loadingScreen.hide();
// Enable/Disable query tool button only if is_query_tool is true.
if (self.sqlServerObject.is_query_tool) {
self.enableSQLEditorButtons();
}
self.sqlServerObject.update_msg_history(false, httpMessage.data.data.result, true);
} else if (ExecuteQuery.isQueryCancelled(httpMessage)) {
self.loadingScreen.hide();
self.sqlServerObject.update_msg_history(false, 'Execution Cancelled!', true);
}
// Enable connection list drop down again for query tool only
if(self.sqlServerObject.is_query_tool && !ExecuteQuery.isQueryStillRunning(httpMessage)){
SqlEditorUtils.disable_connection_dropdown(false);
}
2018-02-09 11:54:42 +00:00
}
).catch(
error => {
// Enable/Disable query tool button only if is_query_tool is true.
self.sqlServerObject.resetQueryHistoryObject(self.sqlServerObject);
2018-02-09 11:54:42 +00:00
self.loadingScreen.hide();
self.sqlServerObject.setIsQueryRunning(false);
2018-02-09 11:54:42 +00:00
if (self.sqlServerObject.is_query_tool) {
self.enableSQLEditorButtons();
SqlEditorUtils.disable_connection_dropdown(false);
2018-02-09 11:54:42 +00:00
}
if(error.response) {
if(ExecuteQuery.wasConnectionLostToPythonServer(error.response)) {
self.handleConnectionToServerLost();
return;
}
const errorData = error.response.data;
if (self.userManagement.isPgaLoginRequired(errorData)) {
return self.userManagement.pgaLogin();
}
2018-02-09 11:54:42 +00:00
let msg = ExecuteQuery.extractErrorMessage(errorData);
2018-02-09 11:54:42 +00:00
self.sqlServerObject.update_msg_history(false, msg);
// Highlight the error in the sql panel
self.sqlServerObject._highlight_error(msg);
} else if(error.request) {
self.handleConnectionToServerLost();
return;
} else {
console.error(error);
}
2018-02-09 11:54:42 +00:00
});
}
initializeExecutionOnSqlEditor(sqlStatement) {
2020-04-10 14:52:41 +05:30
this.loadingScreen.show(gettext('Running query...'));
2018-02-09 11:54:42 +00:00
$('#btn-flash').prop('disabled', true);
this.disableDownloadButton();
2018-02-09 11:54:42 +00:00
this.sqlServerObject.query_start_time = new Date();
if (typeof sqlStatement === 'object') {
2018-02-09 11:54:42 +00:00
this.sqlServerObject.query = sqlStatement['sql'];
} else {
this.sqlServerObject.query = sqlStatement;
}
this.sqlServerObject.rows_affected = 0;
this.sqlServerObject._init_polling_flags();
this.disableSQLEditorButtons();
this.disableTransactionButtons();
2018-02-09 11:54:42 +00:00
}
static prepareAnalyzeSql(sqlStatement, analyzeSql) {
let sqlStatementWithAnalyze = {
sql: sqlStatement,
explain_plan: analyzeSql,
};
return sqlStatementWithAnalyze;
}
onExecuteHTTPError(httpMessage) {
this.loadingScreen.hide();
this.enableSQLEditorButtons();
if (ExecuteQuery.wasConnectionLostToPythonServer(httpMessage.response)) {
2018-02-09 11:54:42 +00:00
this.handleConnectionToServerLost();
return;
}
if (this.userManagement.isPgaLoginRequired(httpMessage.response)) {
2019-08-23 16:15:43 +01:00
this.sqlServerObject.saveState('check_data_changes_to_execute_query', [this.explainPlan]);
this.userManagement.pgaLogin();
2018-02-09 11:54:42 +00:00
}
if (httpErrorHandler.httpResponseRequiresNewTransaction(httpMessage.response)) {
2019-08-23 16:15:43 +01:00
this.sqlServerObject.saveState('check_data_changes_to_execute_query', [this.explainPlan]);
this.sqlServerObject.initTransaction();
2018-02-09 11:54:42 +00:00
}
if (this.wasDatabaseConnectionLost(httpMessage)) {
2019-08-23 16:15:43 +01:00
this.sqlServerObject.saveState('check_data_changes_to_execute_query', [this.explainPlan]);
this.sqlServerObject.handle_connection_lost(false, httpMessage);
2018-02-09 11:54:42 +00:00
}
if(this.isCryptKeyMissing(httpMessage)) {
2019-08-23 16:15:43 +01:00
this.sqlServerObject.saveState('check_data_changes_to_execute_query', [this.explainPlan]);
this.sqlServerObject.handle_cryptkey_missing();
return;
}
let msg = httpMessage.response.data.errormsg;
2018-02-09 11:54:42 +00:00
this.sqlServerObject.update_msg_history(false, msg);
}
wasDatabaseConnectionLost(httpMessage) {
return httpMessage.response.status === 503 &&
httpMessage.response.data.info !== undefined &&
httpMessage.response.data.info === 'CONNECTION_LOST';
}
isCryptKeyMissing(httpMessage) {
return httpMessage.response.status === 503 &&
httpMessage.response.data.info !== undefined &&
httpMessage.response.data.info === 'CRYPTKEY_MISSING';
}
2018-02-09 11:54:42 +00:00
removeGridViewMarker() {
if (this.sqlServerObject.gridView.marker) {
this.sqlServerObject.gridView.marker.clear();
delete this.sqlServerObject.gridView.marker;
this.sqlServerObject.gridView.marker = null;
// Remove already existing marker
this.sqlServerObject.gridView.query_tool_obj.removeLineClass(this.sqlServerObject.marked_line_no, 'wrap', 'CodeMirror-activeline-background');
}
}
disableDownloadButton() {
this.sqlServerObject.enable_disable_download_btn(true);
}
2018-02-09 11:54:42 +00:00
enableSQLEditorButtons() {
this.sqlServerObject.disable_tool_buttons(false);
}
disableSQLEditorButtons() {
this.sqlServerObject.disable_tool_buttons(true);
}
enableTransactionButtons() {
this.sqlServerObject.disable_transaction_buttons(false);
}
disableTransactionButtons() {
this.sqlServerObject.special_sql = undefined;
this.sqlServerObject.disable_transaction_buttons(true);
}
static wasConnectionLostToPythonServer(httpResponse) {
return _.isUndefined(httpResponse) || _.isUndefined(httpResponse.data);
2018-02-09 11:54:42 +00:00
}
handleConnectionToServerLost() {
this.sqlServerObject.update_msg_history(false,
gettext('Not connected to the server or the connection to the server has been closed.')
);
}
updateSqlEditorStateWithInformationFromServer(messageData) {
this.sqlServerObject.can_edit = messageData.can_edit;
this.sqlServerObject.can_filter = messageData.can_filter;
this.sqlServerObject.info_notifier_timeout = messageData.info_notifier_timeout;
}
updateSqlEditorLastTransactionStatus(transactionStatus) {
this.sqlServerObject.last_transaction_status = transactionStatus;
}
2018-02-09 11:54:42 +00:00
static isSqlCorrect(httpMessageData) {
return httpMessageData.data.status;
}
static extractErrorMessage(httpMessage) {
let msg = httpMessage.errormsg;
if (httpMessage.responseJSON !== undefined &&
httpMessage.responseJSON.errormsg !== undefined)
msg = httpMessage.responseJSON.errormsg;
return msg;
}
static isQueryFinished(httpMessage) {
return httpMessage.data.data.status === 'Success';
}
static isQueryStillRunning(httpMessage) {
return httpMessage.data.data.status === 'Busy';
}
static isQueryCancelled(httpMessage) {
return httpMessage.data.data.status === 'Cancel';
}
static isConnectionToServerLostWhilePolling(httpMessage) {
return httpMessage.data.data.status === 'NotConnected';
}
}
module.exports = {
ExecuteQuery: ExecuteQuery,
};