Fix the query tool restore connection issue on the server disconnection from the left side object explorer. #6502

This commit is contained in:
Anil Sahoo 2024-09-02 15:06:11 +05:30 committed by GitHub
parent f451f89d38
commit 8bae604129
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 122 additions and 29 deletions

View File

@ -1377,7 +1377,7 @@ class ServerNode(PGChildNodeView):
}
)
def connect(self, gid, sid):
def connect(self, gid, sid, is_qt=False):
"""
Connect the Server and return the connection object.
Verification Process before Connection:
@ -1443,7 +1443,9 @@ class ServerNode(PGChildNodeView):
# Connect the Server
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
if not manager.connection().connected():
# Update the manager with the server details if not connected and
# the API call is not made from SQL Editor or View/Edit Data tool
if not manager.connection().connected() and not is_qt:
manager.update(server)
conn = manager.connection()

View File

@ -802,6 +802,14 @@ def start_view_data(trans_id):
# Connect to the Server if not connected.
if not default_conn.connected():
view = SchemaDiffRegistry.get_node_view('server')
response = view.connect(trans_obj.sgid,
trans_obj.sid, True)
if response.status_code == 428:
return response
else:
conn = manager.connection(did=trans_obj.did)
status, msg = default_conn.connect()
if not status:
return make_json_response(

View File

@ -333,7 +333,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
}
};
const initializeQueryTool = (password)=>{
const initializeQueryTool = (password, explainObject=null, macroSQL='', executeCursor=false)=>{
let selectedConn = _.find(qtState.connection_list, (c)=>c.is_selected);
let baseUrl = '';
if(qtState.params.is_query_tool) {
@ -364,9 +364,9 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
obtaining_conn: false,
});
if(!qtState.params.is_query_tool) {
eventBus.current.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION);
}
eventBus.current.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, explainObject, macroSQL, executeCursor);
let msg = `${selectedConn['server_name']}/${selectedConn['database_name']} - Database connected`;
pgAdmin.Browser.notifier.success(_.escape(msg));
}).catch((error)=>{
if(error.response?.request?.responseText?.search('Ticket expired') !== -1) {
Kerberos.fetch_ticket()
@ -415,6 +415,8 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
getSQLScript();
initializeQueryTool();
eventBus.current.registerListener(QUERY_TOOL_EVENTS.REINIT_QT_CONNECTION, initializeQueryTool);
eventBus.current.registerListener(QUERY_TOOL_EVENTS.FOCUS_PANEL, (qtPanelId)=>{
docker.current.focus(qtPanelId);
});
@ -684,6 +686,10 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
params: {
...prev.params,
trans_id: respData.data.trans_id,
server_name: connectionData.server_name,
database_name: connectionData.database_name,
dbname: connectionData.database_name,
user: connectionData.user,
sid: connectionData.sid,
did: connectionData.did,
title: connectionData.title,

View File

@ -57,6 +57,7 @@ export const QUERY_TOOL_EVENTS = {
HANDLE_API_ERROR: 'HANDLE_API_ERROR',
SET_FILTER_INFO: 'SET_FILTER_INFO',
FETCH_MORE_ROWS: 'FETCH_MORE_ROWS',
REINIT_QT_CONNECTION:'REINIT_QT_CONNECTION',
EDITOR_LAST_FOCUS: 'EDITOR_LAST_FOCUS',
EDITOR_FIND_REPLACE: 'EDITOR_FIND_REPLACE',

View File

@ -276,10 +276,10 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
}, [queryToolConnCtx.connectionStatus]);
const onCommitClick=()=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, 'COMMIT;', null, true);
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, 'COMMIT;', null, '', true);
};
const onRollbackClick=()=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, 'ROLLBACK;', null, true);
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, 'ROLLBACK;', null, '', true);
};
const executeMacro = (m)=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, null, m.sql);

View File

@ -152,10 +152,10 @@ export default function Query({onTextSelect}) {
query = query || editor.current?.getValue() || '';
}
if(query) {
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, query, explainObject, external, null, executeCursor);
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, query, explainObject, macroSQL, external, null, executeCursor);
}
} else {
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, null, null);
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, null, null, '');
}
};

View File

@ -30,6 +30,7 @@ import EmptyPanelMessage from '../../../../../../static/js/components/EmptyPanel
import { GraphVisualiser } from './GraphVisualiser';
import { usePgAdmin } from '../../../../../../static/js/BrowserComponent';
import pgAdmin from 'sources/pgadmin';
import ConnectServerContent from '../../../../../../static/js/Dialogs/ConnectServerContent';
const StyledBox = styled(Box)(({theme}) => ({
display: 'flex',
@ -39,7 +40,7 @@ const StyledBox = styled(Box)(({theme}) => ({
}));
export class ResultSetUtils {
constructor(api, transId, isQueryTool=true) {
constructor(api, queryToolCtx, transId, isQueryTool=true) {
this.api = api;
this.transId = transId;
this.startTime = new Date();
@ -48,6 +49,7 @@ export class ResultSetUtils {
this.clientPKLastIndex = 0;
this.historyQuerySource = null;
this.hasQueryCommitted = false;
this.queryToolCtx = queryToolCtx;
}
static generateURLReconnectionFlag(baseUrl, transId, shouldReconnect) {
@ -187,8 +189,49 @@ export class ResultSetUtils {
);
}
}
connectServerModal (modalData, connectCallback, cancelCallback) {
this.queryToolCtx.modal.showModal(gettext('Connect to server'), (closeModal)=>{
return (
<ConnectServerContent
closeModal={()=>{
cancelCallback?.();
closeModal();
}}
data={modalData}
onOK={(formData)=>{
connectCallback(Object.fromEntries(formData));
closeModal();
}}
/>
);
}, {
onClose: cancelCallback,
});
};
async connectServer (sid, user, formData, connectCallback) {
try {
let {data: respData} = await this.api({
method: 'POST',
url: url_for('sqleditor.connect_server', {
'sid': sid,
...(user ? {
'usr': user,
}:{}),
}),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: formData
});
connectCallback?.(respData.data);
} catch (error) {
this.connectServerModal(error.response?.data?.result, async (data)=>{
this.connectServer(sid, user, data, connectCallback);
}, ()=>{
/*This is intentional (SonarQube)*/
});
}
};
async startExecution(query, explainObject, onIncorrectSQL, flags={
async startExecution(query, explainObject, macroSQL, onIncorrectSQL, flags={
isQueryTool: true, external: false, reconnect: false, executeCursor: false
}) {
let startTime = new Date();
@ -244,16 +287,26 @@ export class ResultSetUtils {
}
}
} catch(e) {
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_END);
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR,
e,
{
connectionLostCallback: ()=>{
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, query, explainObject, flags.external, true, flags.executeCursor);
},
checkTransaction: true,
}
);
if(e?.response?.status == 428){
this.connectServerModal(e.response?.data?.result, async (passwordData)=>{
await this.connectServer(this.queryToolCtx.params.sid, this.queryToolCtx.params.user, passwordData, async ()=>{
await this.eventBus.fireEvent(QUERY_TOOL_EVENTS.REINIT_QT_CONNECTION, '', explainObject, macroSQL, flags.executeCursor);
});
}, ()=>{
/*This is intentional (SonarQube)*/
});
} else {
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_END);
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR,
e,
{
connectionLostCallback: ()=>{
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, query, explainObject, '', flags.external, true, flags.executeCursor);
},
checkTransaction: true,
}
);
}
}
return false;
}
@ -304,7 +357,7 @@ export class ResultSetUtils {
});
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, error, {
connectionLostCallback: ()=>{
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, this.query, explainObject, flags.external, true, flags.executeCursor);
this.eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, this.query, explainObject, '', flags.external, true, flags.executeCursor);
},
checkTransaction: true,
});
@ -767,7 +820,7 @@ export function ResultSet() {
const [columns, setColumns] = useState([]);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const api = getApiInstance();
const rsu = React.useRef(new ResultSetUtils(api, queryToolCtx.params.trans_id, queryToolCtx.params.is_query_tool));
const rsu = React.useRef(new ResultSetUtils(api, queryToolCtx, queryToolCtx.params.trans_id, queryToolCtx.params.is_query_tool));
const [dataChangeStore, dispatchDataChange] = React.useReducer(dataChangeReducer, {});
const [selectedRows, setSelectedRows] = useState(new Set());
const [selectedColumns, setSelectedColumns] = useState(new Set());
@ -802,7 +855,7 @@ export function ResultSet() {
eventBus.fireEvent(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, selectedRows.size, selectedColumns.size, selectedRange.current, selectedCell.current?.length);
};
const executionStartCallback = async (query, explainObject, external=false, reconnect=false, executeCursor=false)=>{
const executionStartCallback = async (query, explainObject, macroSQL, external=false, reconnect=false, executeCursor=false)=>{
const yesCallback = async ()=>{
/* Reset */
eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, null);
@ -813,7 +866,7 @@ export function ResultSet() {
setLoaderText(gettext('Waiting for the query to complete...'));
setDataOutputQuery(query);
return await rsu.current.startExecution(
query, explainObject,
query, explainObject, macroSQL,
()=>{
setColumns([]);
setRows([]);
@ -852,8 +905,15 @@ export function ResultSet() {
};
const executeAndPoll = async ()=>{
await yesCallback();
pollCallback();
await yesCallback().then((res)=>{
if(res){
pollCallback();
} else {
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_END);
}
}).catch((err)=>{
console.error(err);
});
};
if(isDataChanged()) {
@ -989,7 +1049,7 @@ export function ResultSet() {
e,
{
connectionLostCallback: ()=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, rsu.current.query, null, false, true);
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, rsu.current.query, null, '', false, true);
},
checkTransaction: true,
}

View File

@ -28,6 +28,7 @@ from pgadmin.utils.driver import get_driver
from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost,\
CryptKeyMissing
from pgadmin.utils.constants import ERROR_MSG_TRANS_ID_NOT_FOUND
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
class StartRunningQuery:
@ -81,6 +82,21 @@ class StartRunningQuery:
# Connect to the Server if not connected.
if connect and not conn.connected():
view = SchemaDiffRegistry.get_node_view('server')
response = view.connect(transaction_object.sgid,
transaction_object.sid, True)
if response.status_code == 428:
return response
else:
conn = manager.connection(
did=transaction_object.did,
conn_id=self.connection_id,
auto_reconnect=False,
use_binary_placeholder=True,
array_to_string=True,
**({"database": transaction_object.dbname} if hasattr(
transaction_object, 'dbname') else {}))
status, msg = conn.connect()
if not status:
self.logger.error(msg)