From 0d9c38d221300b13ea87ee310ba7927c435f2032 Mon Sep 17 00:00:00 2001 From: dev-hari-prasad Date: Tue, 9 Jun 2026 21:04:19 +0530 Subject: [PATCH 1/4] Fix query auto execution on session restore - Handle both boolean and string values for is_query_tool - Fix Query Tool tabs being incorrectly detected during restore - Prevent queries from running automatically when restoring a session The issue was caused by is_query_tool only checking for the string 'true'. During session restore the value can come back as a boolean, which caused Query Tool tabs to be treated as View/Edit Data tabs and trigger the auto execution path. --- .../js/components/QueryToolComponent.jsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx index ff642a24357..b3aa2297428 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx @@ -138,7 +138,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN params: { ...params, title: _.unescape(params.title), - is_query_tool: params.is_query_tool == 'true', + is_query_tool: params.is_query_tool === true || params.is_query_tool == 'true', node_name: retrieveNodeName(selectedNodeInfo), dbname: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), server_cursor: preferencesStore.getPreferencesForModule('sqleditor').server_cursor === true, @@ -154,7 +154,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN bgcolor: params.bgcolor, conn_title: getTitle( pgAdmin, null, selectedNodeInfo, true, _.unescape(params.server_name), _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), - _.unescape(params.role) || _.unescape(params.user), params.is_query_tool == 'true'), + _.unescape(params.role) || _.unescape(params.user), params.is_query_tool === true || params.is_query_tool == 'true'), server_name: _.unescape(params.server_name), database_name: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), is_selected: true, @@ -342,7 +342,14 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN if(toolContent?.fileName)eventBus.current.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE_DONE, toolContent.fileName, true); } } - setQtStatePartial({ editor_disabled: false }); + setQtStatePartial(prev => ({ + ...prev, + editor_disabled: false, + params: { + ...prev.params, + restore: 'false' + } + })); }; const initializeQueryTool = (password, explainObject=null, macroSQL='', executeCursor=false, executeServerCursor=false, reexecute=false)=>{ @@ -380,7 +387,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN obtaining_conn: false, }); //this condition works if user is in View/Edit Data or user does not saved server or tunnel password and disconnected the server and executing the query - if(!qtState.params.is_query_tool || reexecute) { + if((!qtState.params.is_query_tool || reexecute) && qtState.params.restore != 'true') { eventBus.current.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, explainObject, macroSQL, executeCursor, executeServerCursor); let msg = `${selectedConn['server_name']}/${selectedConn['database_name']} - Database connected`; pgAdmin.Browser.notifier.success(_.escape(msg)); @@ -907,6 +914,10 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN connection_list: qtState.connection_list, current_file: qtState.current_file, toggleQueryTool: () => setQtStatePartial((prev)=>{ + let panel = qtPanelDocker?.find(qtPanelId); + if (panel?.metaData?.toolUrl) { + panel.metaData.toolUrl = panel.metaData.toolUrl.replace('is_query_tool=false', 'is_query_tool=true'); + } return { ...prev, params: { From 29433f2a467a6d799be05ceb3e2bad7a3291c31c Mon Sep 17 00:00:00 2001 From: dev-hari-prasad Date: Wed, 10 Jun 2026 09:51:02 +0530 Subject: [PATCH 2/4] Clean up QueryToolComponent state and URL handling - Normalize is_query_tool check with strict equality - Normalize restore flag to use boolean types instead of strings - Refactor fragile toolUrl replacement to use URL API with searchParams --- .../static/js/components/QueryToolComponent.jsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx index b3aa2297428..356724b5066 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx @@ -138,7 +138,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN params: { ...params, title: _.unescape(params.title), - is_query_tool: params.is_query_tool === true || params.is_query_tool == 'true', + is_query_tool: params.is_query_tool === true || params.is_query_tool === 'true', node_name: retrieveNodeName(selectedNodeInfo), dbname: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), server_cursor: preferencesStore.getPreferencesForModule('sqleditor').server_cursor === true, @@ -154,7 +154,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN bgcolor: params.bgcolor, conn_title: getTitle( pgAdmin, null, selectedNodeInfo, true, _.unescape(params.server_name), _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), - _.unescape(params.role) || _.unescape(params.user), params.is_query_tool === true || params.is_query_tool == 'true'), + _.unescape(params.role) || _.unescape(params.user), params.is_query_tool === true || params.is_query_tool === 'true'), server_name: _.unescape(params.server_name), database_name: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), is_selected: true, @@ -347,7 +347,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN editor_disabled: false, params: { ...prev.params, - restore: 'false' + restore: false } })); }; @@ -387,7 +387,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN obtaining_conn: false, }); //this condition works if user is in View/Edit Data or user does not saved server or tunnel password and disconnected the server and executing the query - if((!qtState.params.is_query_tool || reexecute) && qtState.params.restore != 'true') { + if((!qtState.params.is_query_tool || reexecute) && qtState.params.restore !== true) { eventBus.current.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, explainObject, macroSQL, executeCursor, executeServerCursor); let msg = `${selectedConn['server_name']}/${selectedConn['database_name']} - Database connected`; pgAdmin.Browser.notifier.success(_.escape(msg)); @@ -916,7 +916,13 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN toggleQueryTool: () => setQtStatePartial((prev)=>{ let panel = qtPanelDocker?.find(qtPanelId); if (panel?.metaData?.toolUrl) { - panel.metaData.toolUrl = panel.metaData.toolUrl.replace('is_query_tool=false', 'is_query_tool=true'); + try { + const url = new URL(panel.metaData.toolUrl, window.location.origin); + url.searchParams.set('is_query_tool', 'true'); + panel.metaData = Object.assign({}, panel.metaData, {toolUrl: url.pathname + url.search + url.hash}); + } catch (e) { + console.warn('Failed to update is_query_tool parameter:', e); + } } return { ...prev, From aefee3f06ccb8ceea0be4876097746e47a58ea93 Mon Sep 17 00:00:00 2001 From: dev-hari-prasad Date: Wed, 10 Jun 2026 10:03:36 +0530 Subject: [PATCH 3/4] Update QueryToolComponent.jsx --- .../static/js/components/QueryToolComponent.jsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx index 356724b5066..65a65c49cdc 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx @@ -139,6 +139,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN ...params, title: _.unescape(params.title), is_query_tool: params.is_query_tool === true || params.is_query_tool === 'true', + restore: params.restore === true || params.restore === 'true', node_name: retrieveNodeName(selectedNodeInfo), dbname: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), server_cursor: preferencesStore.getPreferencesForModule('sqleditor').server_cursor === true, @@ -290,14 +291,14 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN eventBus.current.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err); setQtStatePartial({ editor_disabled: true }); }); - } else if (qtState.params.sql_id && qtState.params.restore != 'true') { + } else if (qtState.params.sql_id && qtState.params.restore !== true) { let sqlValue = localStorage.getItem(qtState.params.sql_id); localStorage.removeItem(qtState.params.sql_id); if (sqlValue) { eventBus.current.fireEvent(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, sqlValue); } setQtStatePartial({ editor_disabled: false }); - } else if (qtState.params.restore == 'true') { + } else if (qtState.params.restore === true) { restoreToolContent(); } else { setQtStatePartial({ editor_disabled: false }); @@ -917,11 +918,13 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN let panel = qtPanelDocker?.find(qtPanelId); if (panel?.metaData?.toolUrl) { try { - const url = new URL(panel.metaData.toolUrl, window.location.origin); + const toolUrl = panel.metaData.toolUrl; + const isAbsolute = toolUrl.includes('://') || toolUrl.startsWith('http'); + const url = isAbsolute ? new URL(toolUrl) : new URL(toolUrl, window.location.origin); url.searchParams.set('is_query_tool', 'true'); - panel.metaData = Object.assign({}, panel.metaData, {toolUrl: url.pathname + url.search + url.hash}); + panel.metaData = Object.assign({}, panel.metaData, {toolUrl: url.toString()}); } catch (e) { - console.warn('Failed to update is_query_tool parameter:', e); + console.warn(`Failed to update is_query_tool parameter for toolUrl "${panel?.metaData?.toolUrl}" using origin "${window.location.origin}":`, e); } } return { @@ -1017,6 +1020,7 @@ QueryToolComponent.propTypes = { bgcolor: PropTypes.string, fgcolor: PropTypes.string, is_query_tool: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]).isRequired, + restore: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), server_cursor: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), user: PropTypes.string, role: PropTypes.string, From b8a2a4e4570bdf587c6ff494625562592bea7486 Mon Sep 17 00:00:00 2001 From: dev-hari-prasad Date: Wed, 10 Jun 2026 10:13:00 +0530 Subject: [PATCH 4/4] Refactoring: Clean up state initialization and URL checks - Extracted isQueryTool to eliminate duplicate checks - Simplified absolute-URL detection to use '://' only --- .../sqleditor/static/js/components/QueryToolComponent.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx index 65a65c49cdc..9dd209c275e 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx @@ -118,6 +118,7 @@ const FIXED_PREF = { export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedNodeInfo, qtPanelDocker, qtPanelId, eventBusObj}) { const containerRef = React.useRef(null); const preferencesStore = usePreferences(); + const isQueryTool = params.is_query_tool === true || params.is_query_tool === 'true'; const [qtState, setQtState] = useState({ preferences: { browser: preferencesStore.getPreferencesForModule('browser'), @@ -138,7 +139,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN params: { ...params, title: _.unescape(params.title), - is_query_tool: params.is_query_tool === true || params.is_query_tool === 'true', + is_query_tool: isQueryTool, restore: params.restore === true || params.restore === 'true', node_name: retrieveNodeName(selectedNodeInfo), dbname: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), @@ -155,7 +156,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN bgcolor: params.bgcolor, conn_title: getTitle( pgAdmin, null, selectedNodeInfo, true, _.unescape(params.server_name), _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), - _.unescape(params.role) || _.unescape(params.user), params.is_query_tool === true || params.is_query_tool === 'true'), + _.unescape(params.role) || _.unescape(params.user), isQueryTool), server_name: _.unescape(params.server_name), database_name: _.unescape(params.database_name) || getDatabaseLabel(selectedNodeInfo), is_selected: true, @@ -919,7 +920,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN if (panel?.metaData?.toolUrl) { try { const toolUrl = panel.metaData.toolUrl; - const isAbsolute = toolUrl.includes('://') || toolUrl.startsWith('http'); + const isAbsolute = toolUrl.includes('://'); const url = isAbsolute ? new URL(toolUrl) : new URL(toolUrl, window.location.origin); url.searchParams.set('is_query_tool', 'true'); panel.metaData = Object.assign({}, panel.metaData, {toolUrl: url.toString()});