diff --git a/web/pgadmin/static/js/keyboard_shortcuts.js b/web/pgadmin/static/js/keyboard_shortcuts.js
index c565b862..101aff5b 100644
--- a/web/pgadmin/static/js/keyboard_shortcuts.js
+++ b/web/pgadmin/static/js/keyboard_shortcuts.js
@@ -282,8 +282,9 @@ function keyboardShortcutsQueryTool(
currLi = currLi.next();
}
- /*do not focus on divider and disabled */
+ /*do not focus on divider, disabled and d-none */
while(currLi.hasClass('dropdown-divider')
+ || currLi.hasClass('d-none')
|| currLi.find('.dropdown-item').first().hasClass('disabled')) {
if(keyCode === UP_KEY) {
currLi = currLi.prev();
diff --git a/web/pgadmin/static/js/sqleditor/query_tool_actions.js b/web/pgadmin/static/js/sqleditor/query_tool_actions.js
index 7739e9b5..2c1be324 100644
--- a/web/pgadmin/static/js/sqleditor/query_tool_actions.js
+++ b/web/pgadmin/static/js/sqleditor/query_tool_actions.js
@@ -26,6 +26,14 @@ let queryToolActions = {
return !$('.explain-timing').hasClass('visibility-hidden');
},
+ _summary: function () {
+ return !$('.explain-summary').hasClass('visibility-hidden');
+ },
+
+ _settings: function () {
+ return !$('.explain-settings').hasClass('visibility-hidden');
+ },
+
_clearMessageTab: function () {
$('.sql-editor-message').html('');
},
@@ -41,36 +49,31 @@ let queryToolActions = {
},
explainAnalyze: function (sqlEditorController) {
- let costEnabled = this._costsEnabled();
- let verbose = this._verbose();
- let buffers = this._buffers();
- let timing = this._timing();
const explainObject = {
format: 'json',
analyze: true,
- verbose: verbose,
- costs: costEnabled,
- buffers: buffers,
- timing: timing,
- summary: false,
+ verbose: this._verbose(),
+ costs: this._costsEnabled(),
+ buffers: this._buffers(),
+ timing: this._timing(),
+ summary: this._summary(),
+ settings: this._settings(),
};
this._clearMessageTab();
sqlEditorController.execute(explainObject);
},
explain: function (sqlEditorController) {
- let costEnabled = this._costsEnabled();
- let verbose = this._verbose();
-
// let explainQuery = `EXPLAIN (FORMAT JSON, ANALYZE OFF, VERBOSE ${verbose}, COSTS ${costEnabled}, BUFFERS OFF, TIMING OFF) `;
const explainObject = {
format: 'json',
analyze: false,
- verbose: verbose,
- costs: costEnabled,
+ verbose: this._verbose(),
+ costs: this._costsEnabled(),
buffers: false,
timing: false,
summary: false,
+ settings: false,
};
this._clearMessageTab();
sqlEditorController.execute(explainObject);
diff --git a/web/pgadmin/static/js/sqleditor/query_tool_preferences.js b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js
index c3906aaa..7fd19b40 100644
--- a/web/pgadmin/static/js/sqleditor/query_tool_preferences.js
+++ b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js
@@ -134,6 +134,20 @@ function updateUIPreferences(sqlEditor) {
$el.find('.explain-timing').addClass('visibility-hidden');
}
+ if (preferences.explain_summary) {
+ $el.find('.explain-summary').removeClass('visibility-hidden');
+ }
+ else {
+ $el.find('.explain-summary').addClass('visibility-hidden');
+ }
+
+ if (preferences.explain_settings) {
+ $el.find('.explain-settings').removeClass('visibility-hidden');
+ }
+ else {
+ $el.find('.explain-settings').addClass('visibility-hidden');
+ }
+
/* Connection status check */
/* remove the status checker if present */
if(sqlEditor.connIntervalId != null) {
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index fbc842fc..62db719d 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -234,6 +234,11 @@ def panel(trans_id, is_query_tool, editor_title):
else:
server_type = None
+ if request.args and request.args['server_ver'] != '':
+ server_ver = request.args['server_ver']
+ else:
+ server_ver = 0
+
# If title has slash(es) in it then replace it
if request.args and request.args['fslashes'] != '':
try:
@@ -311,6 +316,7 @@ def panel(trans_id, is_query_tool, editor_title):
is_desktop_mode=app.PGADMIN_RUNTIME,
is_linux=is_linux_platform,
server_type=server_type,
+ server_ver=server_ver,
client_platform=user_agent.platform,
bgcolor=bgcolor,
fgcolor=fgcolor,
@@ -408,7 +414,8 @@ def initialize_query_tool(sgid, sid, did=None):
return make_json_response(
data={
- 'gridTransId': trans_id
+ 'gridTransId': trans_id,
+ 'serverVersion': manager.version,
}
)
diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js
index cc095194..a405b7de 100644
--- a/web/pgadmin/tools/datagrid/static/js/datagrid.js
+++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js
@@ -275,6 +275,7 @@ define('pgadmin.datagrid', [
baseUrl = url_for('datagrid.panel', url_params) +
'?' + 'query_url=' + encodeURI(trans_obj.sURL) +
'&server_type=' + encodeURIComponent(trans_obj.server_type) +
+ '&server_ver=' + trans_obj.serverVersion+
'&fslashes=' + titileForURLObj.slashLocations;
if (self.preferences.new_browser_tab) {
@@ -283,12 +284,6 @@ define('pgadmin.datagrid', [
// add a load listener to the window so that the title gets changed on page load
newWin.addEventListener('load', function() {
newWin.document.title = panel_title;
-
- /* Set the initial version of pref cache the new window is having
- * This will be used by the poller to compare with window openers
- * pref cache version
- */
- //newWin.pgAdmin.Browser.preference_version(pgBrowser.preference_version());
});
} else {
diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
index f138b9a4..65b6c4ec 100644
--- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html
+++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
@@ -285,6 +285,18 @@
{{ _('Timing') }}
+
+
+
+ {{ _('Summary') }}
+
+
+
+
+
+ {{ _('Settings') }}
+
+
@@ -412,7 +424,8 @@
script_type_url,
"{{ server_type }}",
{{ url_params|safe}},
- '{{ layout|safe }}'
+ '{{ layout|safe }}',
+ {{ server_ver }}
);
});
{% endblock %}
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index ac923a55..1d2796ec 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -95,7 +95,6 @@ class SqlEditorModule(PgAdminModule):
return [
'sqleditor.view_data_start',
'sqleditor.query_tool_start',
- 'sqleditor.query_tool_preferences',
'sqleditor.poll',
'sqleditor.fetch',
'sqleditor.fetch_all',
@@ -330,38 +329,6 @@ def extract_sql_from_network_parameters(request_data, request_arguments,
return request_arguments or request_form_data
-@blueprint.route(
- '/query_tool/preferences/',
- methods=["PUT"], endpoint='query_tool_preferences'
-)
-@login_required
-def preferences(trans_id):
- """
- This method is used to get/put explain options from/to preferences
-
- Args:
- trans_id: unique transaction id
- """
-
- data = None
- if request.data:
- data = json.loads(request.data, encoding='utf-8')
- else:
- data = request.args or request.form
- for k, v in data.items():
- v = bool(v)
- if k == 'explain_verbose':
- blueprint.explain_verbose.set(v)
- elif k == 'explain_costs':
- blueprint.explain_costs.set(v)
- elif k == 'explain_buffers':
- blueprint.explain_buffers.set(v)
- elif k == 'explain_timing':
- blueprint.explain_timing.set(v)
-
- return success_return()
-
-
@blueprint.route('/poll/', methods=["GET"], endpoint='poll')
@login_required
def poll(trans_id):
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index a8560574..4c27ae59 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -81,6 +81,7 @@ define('tools.querytool', [
this.handler.preferences = this.preferences;
this.connIntervalId = null;
this.layout = opts.layout;
+ this.set_server_version(opts.server_ver);
},
// Bind all the events
@@ -121,6 +122,8 @@ define('tools.querytool', [
'click #btn-explain-costs': 'on_explain_costs',
'click #btn-explain-buffers': 'on_explain_buffers',
'click #btn-explain-timing': 'on_explain_timing',
+ 'click #btn-explain-summary': 'on_explain_summary',
+ 'click #btn-explain-settings': 'on_explain_settings',
'change .limit': 'on_limit_change',
'keydown': 'keyAction',
// Comment options
@@ -166,6 +169,22 @@ define('tools.querytool', [
docker.addPanel('notifications', wcDocker.DOCK.STACKED, data_output_panel);
},
+ set_server_version: function(server_ver) {
+ let self = this;
+ self.server_ver = server_ver;
+
+ this.$el.find('*[data-min-ver]').map(function() {
+ let minVer = 0,
+ ele = $(this);
+ minVer = parseInt(ele.attr('data-min-ver'));
+ if(minVer > self.server_ver) {
+ ele.addClass('d-none');
+ } else {
+ ele.removeClass('d-none');
+ }
+ });
+ },
+
// This function is used to render the template.
render: function() {
var self = this;
@@ -1833,6 +1852,31 @@ define('tools.querytool', [
);
},
+ on_explain_summary: function(ev) {
+ var self = this;
+
+ this._stopEventPropogation(ev);
+
+ self.handler.trigger(
+ 'pgadmin-sqleditor:button:explain-summary',
+ self,
+ self.handler
+ );
+ },
+
+ on_explain_settings: function(ev) {
+ var self = this;
+
+ this._stopEventPropogation(ev);
+
+ self.handler.trigger(
+ 'pgadmin-sqleditor:button:explain-settings',
+ self,
+ self.handler
+ );
+ },
+
+
do_not_close_menu: function(ev) {
ev.stopPropagation();
},
@@ -2095,7 +2139,7 @@ define('tools.querytool', [
* header and loading icon and start execution of the sql query.
*/
start: function(transId, is_query_tool, editor_title, script_type_url,
- server_type, url_params, layout
+ server_type, url_params, layout, server_ver
) {
var self = this;
@@ -2118,6 +2162,7 @@ define('tools.querytool', [
el: self.container,
handler: self,
layout: layout,
+ server_ver: server_ver,
});
self.transId = self.gridView.transId = transId;
@@ -2211,6 +2256,8 @@ define('tools.querytool', [
self.on('pgadmin-sqleditor:button:explain-costs', self._explain_costs, self);
self.on('pgadmin-sqleditor:button:explain-buffers', self._explain_buffers, self);
self.on('pgadmin-sqleditor:button:explain-timing', self._explain_timing, self);
+ self.on('pgadmin-sqleditor:button:explain-summary', self._explain_summary, self);
+ self.on('pgadmin-sqleditor:button:explain-settings', self._explain_settings, self);
// Indentation related
self.on('pgadmin-sqleditor:indent_selected_code', self._indent_selected_code, self);
self.on('pgadmin-sqleditor:unindent_selected_code', self._unindent_selected_code, self);
@@ -3866,108 +3913,37 @@ define('tools.querytool', [
},
- explainPreferenceUpdate: function(subItem, data, caller) {
- let self = this;
- $.ajax({
- url: url_for('sqleditor.query_tool_preferences', {
- 'trans_id': self.transId,
- }),
- method: 'PUT',
- contentType: 'application/json',
- data: JSON.stringify(data),
- })
- .done(function(res) {
- if (res.success == undefined || !res.success) {
- alertify.alert(gettext('Explain options error'),
- gettext('Error occurred while setting %(subItem)s option in explain.',
- {subItem : subItem})
- );
- }
- else
- self.call_cache_preferences();
- })
- .fail(function(e) {
- let msg = httpErrorHandler.handleQueryToolAjaxError(
- pgAdmin, self, e, caller, [], true
- );
- alertify.alert(gettext('Explain options error'), msg);
- });
+ _toggle_explain_option: function(type) {
+ let selector = `.explain-${type}`;
+ $(selector).toggleClass('visibility-hidden');
},
// This function will toggle "verbose" option in explain
_explain_verbose: function() {
- var self = this;
- let explain_verbose = false;
- if ($('.explain-verbose').hasClass('visibility-hidden') === true) {
- $('.explain-verbose').removeClass('visibility-hidden');
- explain_verbose = true;
- } else {
- $('.explain-verbose').addClass('visibility-hidden');
- explain_verbose = false;
- }
-
- self.explainPreferenceUpdate(
- 'verbose', {
- 'explain_verbose': explain_verbose,
- }, '_explain_verbose'
- );
+ this._toggle_explain_option('verbose');
},
// This function will toggle "costs" option in explain
_explain_costs: function() {
- var self = this;
- let explain_costs = false;
- if ($('.explain-costs').hasClass('visibility-hidden') === true) {
- $('.explain-costs').removeClass('visibility-hidden');
- explain_costs = true;
- } else {
- $('.explain-costs').addClass('visibility-hidden');
- explain_costs = false;
- }
-
- self.explainPreferenceUpdate(
- 'costs', {
- 'explain_costs': explain_costs,
- }, '_explain_costs'
- );
+ this._toggle_explain_option('costs');
},
// This function will toggle "buffers" option in explain
_explain_buffers: function() {
- var self = this;
- let explain_buffers = false;
- if ($('.explain-buffers').hasClass('visibility-hidden') === true) {
- $('.explain-buffers').removeClass('visibility-hidden');
- explain_buffers = true;
- } else {
- $('.explain-buffers').addClass('visibility-hidden');
- explain_buffers = false;
- }
-
- self.explainPreferenceUpdate(
- 'buffers', {
- 'explain_buffers': explain_buffers,
- }, '_explain_buffers'
- );
+ this._toggle_explain_option('buffers');
},
// This function will toggle "timing" option in explain
_explain_timing: function() {
- var self = this;
- let explain_timing = false;
- if ($('.explain-timing').hasClass('visibility-hidden') === true) {
- $('.explain-timing').removeClass('visibility-hidden');
- explain_timing = true;
- } else {
- $('.explain-timing').addClass('visibility-hidden');
- explain_timing = false;
- }
+ this._toggle_explain_option('timing');
+ },
- self.explainPreferenceUpdate(
- 'timing', {
- 'explain_timing': explain_timing,
- }, '_explain_timing'
- );
+ _explain_summary: function() {
+ this._toggle_explain_option('summary');
+ },
+
+ _explain_settings: function() {
+ this._toggle_explain_option('settings');
},
/*
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/12_plus/explain_plan.sql b/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/12_plus/explain_plan.sql
new file mode 100644
index 00000000..0bafcab5
--- /dev/null
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/12_plus/explain_plan.sql
@@ -0,0 +1,17 @@
+EXPLAIN ({% if format -%}
+ FORMAT {{ format.upper() }},
+{%- endif %}{% if analyze is defined -%}
+ ANALYZE {{ analyze }},
+{%- endif %}{% if verbose is defined -%}
+ VERBOSE {{ verbose }},
+{%- endif %}{% if costs is defined -%}
+ COSTS {{ costs }},
+{%- endif %}{% if timing is defined -%}
+ TIMING {{ timing }},
+{%- endif %}{% if summary is defined -%}
+ SUMMARY {{ summary }},
+{%- endif %}{% if settings is defined -%}
+ SETTINGS {{ settings }},
+{%- endif %}{% if buffers is defined -%}
+ BUFFERS {{ buffers }}
+{%- endif %}) {{ sql }}
diff --git a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py
index ca09eaec..64c75754 100644
--- a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py
+++ b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py
@@ -62,6 +62,18 @@ def RegisterQueryToolPreferences(self):
category_label=gettext('Explain')
)
+ self.explain_summary = self.preference.register(
+ 'Explain', 'explain_summary',
+ gettext("Show summary?"), 'boolean', False,
+ category_label=gettext('Explain')
+ )
+
+ self.explain_settings = self.preference.register(
+ 'Explain', 'explain_settings',
+ gettext("Show settings?"), 'boolean', False,
+ category_label=gettext('Explain')
+ )
+
self.auto_commit = self.preference.register(
'Options', 'auto_commit',
gettext("Auto commit?"), 'boolean', True,
diff --git a/web/regression/javascript/sqleditor/query_tool_actions_spec.js b/web/regression/javascript/sqleditor/query_tool_actions_spec.js
index b2b4e871..005e15e3 100644
--- a/web/regression/javascript/sqleditor/query_tool_actions_spec.js
+++ b/web/regression/javascript/sqleditor/query_tool_actions_spec.js
@@ -55,6 +55,8 @@ describe('queryToolActions', () => {
spyOn(queryToolActions, '_costsEnabled').and.returnValue(false);
spyOn(queryToolActions, '_buffers').and.returnValue(false);
spyOn(queryToolActions, '_timing').and.returnValue(false);
+ spyOn(queryToolActions, '_summary').and.returnValue(false);
+ spyOn(queryToolActions, '_settings').and.returnValue(false);
});
it('calls the execute function', () => {
@@ -69,19 +71,22 @@ describe('queryToolActions', () => {
buffers: false,
timing: false,
summary: false,
+ settings: false,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
});
});
- describe('when verbose and costs and buffers and timing are all selected', () => {
+ describe('when all options are selected', () => {
beforeEach(() => {
setUpSpies('', '');
spyOn(queryToolActions, '_verbose').and.returnValue(true);
spyOn(queryToolActions, '_costsEnabled').and.returnValue(true);
spyOn(queryToolActions, '_buffers').and.returnValue(true);
spyOn(queryToolActions, '_timing').and.returnValue(true);
+ spyOn(queryToolActions, '_summary').and.returnValue(true);
+ spyOn(queryToolActions, '_settings').and.returnValue(true);
});
it('calls the execute function', () => {
queryToolActions.explainAnalyze(sqlEditorController);
@@ -92,7 +97,8 @@ describe('queryToolActions', () => {
costs: true,
buffers: true,
timing: true,
- summary: false,
+ summary: true,
+ settings: true,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
});
@@ -105,6 +111,8 @@ describe('queryToolActions', () => {
spyOn(queryToolActions, '_costsEnabled').and.returnValue(false);
spyOn(queryToolActions, '_buffers').and.returnValue(true);
spyOn(queryToolActions, '_timing').and.returnValue(false);
+ spyOn(queryToolActions, '_summary').and.returnValue(false);
+ spyOn(queryToolActions, '_settings').and.returnValue(false);
});
it('calls the execute function', () => {
queryToolActions.explainAnalyze(sqlEditorController);
@@ -117,6 +125,7 @@ describe('queryToolActions', () => {
buffers: true,
timing: false,
summary: false,
+ settings: false,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
@@ -130,6 +139,8 @@ describe('queryToolActions', () => {
spyOn(queryToolActions, '_costsEnabled').and.returnValue(true);
spyOn(queryToolActions, '_buffers').and.returnValue(false);
spyOn(queryToolActions, '_timing').and.returnValue(true);
+ spyOn(queryToolActions, '_summary').and.returnValue(false);
+ spyOn(queryToolActions, '_settings').and.returnValue(false);
});
it('calls the execute function', () => {
queryToolActions.explainAnalyze(sqlEditorController);
@@ -142,6 +153,35 @@ describe('queryToolActions', () => {
buffers: false,
timing: true,
summary: false,
+ settings: false,
+ };
+
+ expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
+ });
+ });
+
+ describe('when all are not selected except summary and settings', () => {
+ beforeEach(() => {
+ setUpSpies('', '');
+ spyOn(queryToolActions, '_verbose').and.returnValue(false);
+ spyOn(queryToolActions, '_costsEnabled').and.returnValue(false);
+ spyOn(queryToolActions, '_buffers').and.returnValue(false);
+ spyOn(queryToolActions, '_timing').and.returnValue(false);
+ spyOn(queryToolActions, '_summary').and.returnValue(true);
+ spyOn(queryToolActions, '_settings').and.returnValue(true);
+ });
+ it('calls the execute function', () => {
+ queryToolActions.explainAnalyze(sqlEditorController);
+
+ const explainObject = {
+ format: 'json',
+ analyze: true,
+ verbose: false,
+ costs: false,
+ buffers: false,
+ timing: false,
+ summary: true,
+ settings: true,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
@@ -155,6 +195,10 @@ describe('queryToolActions', () => {
setUpSpies('', '');
spyOn(queryToolActions, '_verbose').and.returnValue(true);
spyOn(queryToolActions, '_costsEnabled').and.returnValue(true);
+ spyOn(queryToolActions, '_summary').and.returnValue(false);
+ spyOn(queryToolActions, '_settings').and.returnValue(false);
+ spyOn(queryToolActions, '_summary').and.returnValue(false);
+ spyOn(queryToolActions, '_settings').and.returnValue(false);
});
it('calls the execute function', () => {
@@ -167,6 +211,7 @@ describe('queryToolActions', () => {
buffers: false,
timing: false,
summary: false,
+ settings: false,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
});
@@ -189,6 +234,7 @@ describe('queryToolActions', () => {
buffers: false,
timing: false,
summary: false,
+ settings: false,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
@@ -212,6 +258,7 @@ describe('queryToolActions', () => {
buffers: false,
timing: false,
summary: false,
+ settings: false,
};
expect(sqlEditorController.execute).toHaveBeenCalledWith(explainObject);
});