public inbox for [email protected]help / color / mirror / Atom feed
[pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 12+ messages / 2 participants [nested] [flat]
* [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-06-29 08:55 Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-06-29 08:55 UTC (permalink / raw) To: pgadmin-hackers Hi Hackers, Attached is the patch to fix the RM #3397 Add support for JIT stats in EXPLAIN output in PG11. Please review it. -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [application/octet-stream] RM_3397.patch (8.8K, 3-RM_3397.patch) download | inline diff: diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ac463d3..226b323 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -104,6 +104,16 @@ class QueryToolFeatureTest(BaseFeatureTest): self._query_tool_notify_statements() self._clear_query_tool() + # explain query with JIT stats + print("Explain query with JIT stats... ", + file=sys.stderr, end="") + if self._supported_jit_on_server(): + self._query_tool_explain_check_jit_stats() + print("OK.", file=sys.stderr) + self._clear_query_tool() + else: + print("Skipped.", file=sys.stderr) + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -660,9 +670,62 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) + self._clear_query_tool() else: print("Skipped.", file=sys.stderr) + def _supported_jit_on_server(self): + connection = test_utils.get_db_connection( + self.server['db'], + self.server['username'], + self.server['db_password'], + self.server['host'], + self.server['port'], + self.server['sslmode'] + ) + + pg_cursor = connection.cursor() + pg_cursor.execute('select version()') + version_string = pg_cursor.fetchone() + + is_edb = False + if len(version_string) > 0: + is_edb = 'EnterpriseDB' in version_string[0] + + connection.close() + + return connection.server_version >= 110000 and not is_edb + + def _query_tool_explain_check_jit_stats(self): + wait = WebDriverWait(self.page.driver, 10) + + self.page.fill_codemirror_area_with("SET jit_above_cost=10;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self._clear_query_tool() + + self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;") + query_op = self.page.find_by_id("btn-query-dropdown") + query_op.click() + ActionChains(self.driver).move_to_element( + query_op.find_element_by_xpath( + "//li[contains(.,'Explain Options')]")).perform() + + self.page.find_by_id("btn-explain-verbose").click() + self.page.find_by_id("btn-explain-costs").click() + self.page.find_by_id("btn-explain-analyze").click() + + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Data Output') + + canvas = wait.until(EC.presence_of_element_located( + (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")) + ) + # Search for 'Output' word in result (verbose option) + canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]") + + self._clear_query_tool() + class WaitForAnyElementWithText(object): def __init__(self, locator, text): diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css index d549f85..34fa74f 100644 --- a/web/pgadmin/misc/static/explain/css/explain.css +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -17,6 +17,26 @@ opacity: 1; } +.pg-explain-stats-area { + position: absolute; + top: 5px; + right: 25px; + opacity: 0.5; +} + +.pg-explain-stats-btn { + top: 5px; + min-width: 25px; + border: 1px solid transparent; +} +.pg-explain-stats-btn.disabled { + cursor: auto !important; +} + +.pg-explain-stats-area:hover { + opacity: 1; +} + .explain-tooltip { display: table-cell; text-align: left; @@ -55,4 +75,4 @@ td.explain-tooltip-val { height: 100%; width: 100%; overflow: auto; -} \ No newline at end of file +} diff --git a/web/pgadmin/misc/static/explain/js/explain.js b/web/pgadmin/misc/static/explain/js/explain.js index e028774..1ad25df 100644 --- a/web/pgadmin/misc/static/explain/js/explain.js +++ b/web/pgadmin/misc/static/explain/js/explain.js @@ -687,6 +687,83 @@ define('pgadmin.misc.explain', [ }, }); + // Backbone model for other statistics + var StatsModel = Backbone.Model.extend({ + defaults: { + JIT: [], + Triggers: [], + }, + set_statistics: function(xpos, ypos, graphContainer, toolTipContainer) { + var jit_stats = this.get('JIT'), + triggers_stats = this.get('Triggers'); + $('#btn-explain-stats').on('mouseover', () => { + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + if (Object.keys(jit_stats).length == 0 && + Object.keys(triggers_stats).length == 0) { + return; + } + + var tooltip = $('<table></table>', { + class: 'pgadmin-tooltip-table', + }).appendTo(toolTipContainer); + + if (Object.keys(jit_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">JIT:</td></tr>'); + _.each(jit_stats, function(value, key) { + tooltip.append('<tr><td class="label explain-tooltip">  ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + }); + } + + if (Object.keys(triggers_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">Triggers:</td></tr>'); + _.each(triggers_stats, function(triggers, key_id) { + if (triggers instanceof Object) { + _.each(triggers, function(value, key) { + if (key === 'Trigger Name') { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } + }); + } + else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key_id + '</td><td class="label explain-tooltip-val">' + + triggers + '</td></tr>'); + } + }); + } + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({ + 'opacity': '0.8', + 'left': '', + 'right': '65px', + 'top': '15px', + }); + }); + + // Remove tooltip when mouse is out from node's area + $('#btn-explain-stats').on('mouseout', () => { + toolTipContainer.empty(); + toolTipContainer.css({ + 'opacity': '0', + 'left': 0, + 'top': 0, + }); + + }); + }, + }); + // Main backbone model to store JSON object var MainPlanModel = Backbone.Model.extend({ defaults: { @@ -696,6 +773,7 @@ define('pgadmin.misc.explain', [ }, initialize: function() { this.set('Plan', new PlanModel()); + this.set('Statistics', new StatsModel()); }, // Parse the JSON data and fetch its children plans @@ -718,6 +796,17 @@ define('pgadmin.misc.explain', [ delete data['Plan']; } + var stats = this.get('Statistics'); + if (data && 'JIT' in data) { + stats.set('JIT', data['JIT']); + delete data ['JIT']; + } + + if (data && 'Triggers' in data) { + stats.set('Triggers', data['Triggers']); + delete data ['Triggers']; + } + return data; }, toJSON: function() { @@ -745,6 +834,10 @@ define('pgadmin.misc.explain', [ plan.draw( g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer ); + + //Set the Statistics as tooltip + var stats = this.get('Statistics'); + stats.set_statistics(xpos, ypos, graphContainer, toolTipContainer); }, }); @@ -784,6 +877,21 @@ define('pgadmin.misc.explain', [ class: 'fa fa-search-minus', })); + var statsArea = $('<div></div>', { + class: 'pg-explain-stats-area btn-group', + role: 'group', + }).appendTo(container); + + $('<button></button>', { + id: 'btn-explain-stats', + class: 'btn pg-explain-stats-btn badge disabled', + title: 'Statistics', + tabindex: 0, + }).appendTo(statsArea).append( + $('<i></i>', { + class: 'fa fa-line-chart', + })); + // Main div to be drawn all images on var planDiv = $('<div></div>', { class: 'pgadmin-explain-container', ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-06-29 13:26 Dave Page <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Dave Page @ 2018-06-29 13:26 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi <[email protected] > wrote: > Hi Hackers, > > Attached is the patch to fix the RM #3397 Add support for JIT stats in > EXPLAIN output in PG11. Please review it. > A couple of immediate thoughts: - When the canvas is first rendered, there's a vertical scrollbar now. As soon as I mouseover the new icon, it vanishes and the icon jumps to the right. - The icon seems lighter than the other controls on the left. - The icon isn't disabled when there is no info to show. Thanks. -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-06-29 14:12 Akshay Joshi <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-06-29 14:12 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi Dave On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: > Hi > > On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < > [email protected]> wrote: > >> Hi Hackers, >> >> Attached is the patch to fix the RM #3397 Add support for JIT stats in >> EXPLAIN output in PG11. Please review it. >> > > A couple of immediate thoughts: > > - When the canvas is first rendered, there's a vertical scrollbar now. As > soon as I mouseover the new icon, it vanishes and the icon jumps to the > right. > Will look into it. Vertical scrollbar comes even if you remove my patch and try to hover any image. > > - The icon seems lighter than the other controls on the left. > Same css has been applied, only difference is button is disabled. > > - The icon isn't disabled when there is no info to show. > Button is always disabled, I have just change the opacity. > > Thanks. > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-06-29 14:15 Dave Page <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Dave Page @ 2018-06-29 14:15 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi <[email protected] > wrote: > Hi Dave > > On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: > >> Hi >> >> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the patch to fix the RM #3397 Add support for JIT stats in >>> EXPLAIN output in PG11. Please review it. >>> >> >> A couple of immediate thoughts: >> >> - When the canvas is first rendered, there's a vertical scrollbar now. As >> soon as I mouseover the new icon, it vanishes and the icon jumps to the >> right. >> > > Will look into it. Vertical scrollbar comes even if you remove my > patch and try to hover any image. > >> >> - The icon seems lighter than the other controls on the left. >> > > Same css has been applied, only difference is button is disabled. > >> >> - The icon isn't disabled when there is no info to show. >> > > Button is always disabled, I have just change the opacity. > >> >> Thanks. >> > Maybe - but I can still click it and it reacts as if it's active. It may be lighter to indicate that it's disabled, but its not behaving as such. -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-06-30 08:15 Akshay Joshi <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-06-30 08:15 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi Dave On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: > > > On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < > [email protected]> wrote: > >> Hi Dave >> >> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: >> >>> Hi >>> >>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>> [email protected]> wrote: >>> >>>> Hi Hackers, >>>> >>>> Attached is the patch to fix the RM #3397 Add support for JIT stats in >>>> EXPLAIN output in PG11. Please review it. >>>> >>> >>> A couple of immediate thoughts: >>> >>> - When the canvas is first rendered, there's a vertical scrollbar now. >>> As soon as I mouseover the new icon, it vanishes and the icon jumps to the >>> right. >>> >> >> Will look into it. Vertical scrollbar comes even if you remove my >> patch and try to hover any image. >> >>> >>> - The icon seems lighter than the other controls on the left. >>> >> >> Same css has been applied, only difference is button is disabled. >> >>> >>> - The icon isn't disabled when there is no info to show. >>> >> >> Button is always disabled, I have just change the opacity. >> >>> >>> Thanks. >>> >> > Maybe - but I can still click it and it reacts as if it's active. It may > be lighter to indicate that it's disabled, but its not behaving as such. > Attached is the modified patch. Please review it. > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [application/octet-stream] RM_3397_v2.patch (9.3K, 3-RM_3397_v2.patch) download | inline diff: diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ac463d3..226b323 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -104,6 +104,16 @@ class QueryToolFeatureTest(BaseFeatureTest): self._query_tool_notify_statements() self._clear_query_tool() + # explain query with JIT stats + print("Explain query with JIT stats... ", + file=sys.stderr, end="") + if self._supported_jit_on_server(): + self._query_tool_explain_check_jit_stats() + print("OK.", file=sys.stderr) + self._clear_query_tool() + else: + print("Skipped.", file=sys.stderr) + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -660,9 +670,62 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) + self._clear_query_tool() else: print("Skipped.", file=sys.stderr) + def _supported_jit_on_server(self): + connection = test_utils.get_db_connection( + self.server['db'], + self.server['username'], + self.server['db_password'], + self.server['host'], + self.server['port'], + self.server['sslmode'] + ) + + pg_cursor = connection.cursor() + pg_cursor.execute('select version()') + version_string = pg_cursor.fetchone() + + is_edb = False + if len(version_string) > 0: + is_edb = 'EnterpriseDB' in version_string[0] + + connection.close() + + return connection.server_version >= 110000 and not is_edb + + def _query_tool_explain_check_jit_stats(self): + wait = WebDriverWait(self.page.driver, 10) + + self.page.fill_codemirror_area_with("SET jit_above_cost=10;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self._clear_query_tool() + + self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;") + query_op = self.page.find_by_id("btn-query-dropdown") + query_op.click() + ActionChains(self.driver).move_to_element( + query_op.find_element_by_xpath( + "//li[contains(.,'Explain Options')]")).perform() + + self.page.find_by_id("btn-explain-verbose").click() + self.page.find_by_id("btn-explain-costs").click() + self.page.find_by_id("btn-explain-analyze").click() + + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Data Output') + + canvas = wait.until(EC.presence_of_element_located( + (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")) + ) + # Search for 'Output' word in result (verbose option) + canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]") + + self._clear_query_tool() + class WaitForAnyElementWithText(object): def __init__(self, locator, text): diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css index d549f85..38bb322 100644 --- a/web/pgadmin/misc/static/explain/css/explain.css +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -17,6 +17,18 @@ opacity: 1; } +.pg-explain-stats-area { + position: absolute; + top: 5px; + right: 25px; +} + +.pg-explain-stats-btn { + top: 5px; + min-width: 25px; + border: 1px solid transparent; +} + .explain-tooltip { display: table-cell; text-align: left; @@ -37,8 +49,6 @@ td.explain-tooltip-val { .pgadmin-explain-tooltip { position: absolute; - padding:5px; - border: 1px solid white; opacity:0; color: cornsilk; background-color: #010125; @@ -55,4 +65,4 @@ td.explain-tooltip-val { height: 100%; width: 100%; overflow: auto; -} \ No newline at end of file +} diff --git a/web/pgadmin/misc/static/explain/js/explain.js b/web/pgadmin/misc/static/explain/js/explain.js index e028774..04cc7f8 100644 --- a/web/pgadmin/misc/static/explain/js/explain.js +++ b/web/pgadmin/misc/static/explain/js/explain.js @@ -615,6 +615,9 @@ define('pgadmin.misc.explain', [ }); toolTipContainer.css('left', toolTipX); toolTipContainer.css('top', toolTipY); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); }); // Remove tooltip when mouse is out from node's area @@ -687,6 +690,85 @@ define('pgadmin.misc.explain', [ }, }); + // Backbone model for other statistics + var StatsModel = Backbone.Model.extend({ + defaults: { + JIT: [], + Triggers: [], + }, + set_statistics: function(xpos, ypos, graphContainer, toolTipContainer) { + var jit_stats = this.get('JIT'), + triggers_stats = this.get('Triggers'); + $('.pg-explain-stats-area').on('mouseover', () => { + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + if (Object.keys(jit_stats).length == 0 && + Object.keys(triggers_stats).length == 0) { + return; + } + + var tooltip = $('<table></table>', { + class: 'pgadmin-tooltip-table', + }).appendTo(toolTipContainer); + + if (Object.keys(jit_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">JIT:</td></tr>'); + _.each(jit_stats, function(value, key) { + tooltip.append('<tr><td class="label explain-tooltip">  ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + }); + } + + if (Object.keys(triggers_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">Triggers:</td></tr>'); + _.each(triggers_stats, function(triggers, key_id) { + if (triggers instanceof Object) { + _.each(triggers, function(value, key) { + if (key === 'Trigger Name') { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } + }); + } + else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key_id + '</td><td class="label explain-tooltip-val">' + + triggers + '</td></tr>'); + } + }); + } + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({ + 'opacity': '0.8', + 'left': '', + 'right': '65px', + 'top': '15px', + }); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); + }); + + // Remove tooltip when mouse is out from node's area + $('.pg-explain-stats-area').on('mouseout', () => { + toolTipContainer.empty(); + toolTipContainer.css({ + 'opacity': '0', + 'left': 0, + 'top': 0, + }); + }); + }, + }); + // Main backbone model to store JSON object var MainPlanModel = Backbone.Model.extend({ defaults: { @@ -696,6 +778,7 @@ define('pgadmin.misc.explain', [ }, initialize: function() { this.set('Plan', new PlanModel()); + this.set('Statistics', new StatsModel()); }, // Parse the JSON data and fetch its children plans @@ -718,6 +801,17 @@ define('pgadmin.misc.explain', [ delete data['Plan']; } + var stats = this.get('Statistics'); + if (data && 'JIT' in data) { + stats.set('JIT', data['JIT']); + delete data ['JIT']; + } + + if (data && 'Triggers' in data) { + stats.set('Triggers', data['Triggers']); + delete data ['Triggers']; + } + return data; }, toJSON: function() { @@ -745,6 +839,10 @@ define('pgadmin.misc.explain', [ plan.draw( g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer ); + + //Set the Statistics as tooltip + var stats = this.get('Statistics'); + stats.set_statistics(xpos, ypos, graphContainer, toolTipContainer); }, }); @@ -784,6 +882,22 @@ define('pgadmin.misc.explain', [ class: 'fa fa-search-minus', })); + var statsArea = $('<div></div>', { + class: 'pg-explain-stats-area btn-group', + role: 'group', + }).appendTo(container); + + $('<button></button>', { + id: 'btn-explain-stats', + class: 'btn pg-explain-stats-btn badge', + title: 'Statistics', + tabindex: 0, + disabled: 'disabled', + }).appendTo(statsArea).append( + $('<i></i>', { + class: 'fa fa-line-chart', + })); + // Main div to be drawn all images on var planDiv = $('<div></div>', { class: 'pgadmin-explain-container', ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-02 10:40 Dave Page <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Dave Page @ 2018-07-02 10:40 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi <[email protected] > wrote: > Hi Dave > > On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: > >> >> >> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Dave >>> >>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: >>> >>>> Hi >>>> >>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>> [email protected]> wrote: >>>> >>>>> Hi Hackers, >>>>> >>>>> Attached is the patch to fix the RM #3397 Add support for JIT stats >>>>> in EXPLAIN output in PG11. Please review it. >>>>> >>>> >>>> A couple of immediate thoughts: >>>> >>>> - When the canvas is first rendered, there's a vertical scrollbar now. >>>> As soon as I mouseover the new icon, it vanishes and the icon jumps to the >>>> right. >>>> >>> >>> Will look into it. Vertical scrollbar comes even if you remove my >>> patch and try to hover any image. >>> >>>> >>>> - The icon seems lighter than the other controls on the left. >>>> >>> >>> Same css has been applied, only difference is button is disabled. >>> >>>> >>>> - The icon isn't disabled when there is no info to show. >>>> >>> >>> Button is always disabled, I have just change the opacity. >>> >>>> >>>> Thanks. >>>> >>> >> Maybe - but I can still click it and it reacts as if it's active. It may >> be lighter to indicate that it's disabled, but its not behaving as such. >> > > Attached is the modified patch. Please review it. > The button still changes foreground colour on mouseover when disabled. I think it needs to be completely non-reactive when disabled. It should also be a noticably lighter shade when disabled; right now it seems to be darker than the other buttons (see attached). -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company Attachments: [image/png] Screen Shot 2018-07-02 at 11.39.56.png (244.7K, 3-Screen%20Shot%202018-07-02%20at%2011.39.56.png) download | view image ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-03 07:05 Akshay Joshi <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-07-03 07:05 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi Dave, On Mon, Jul 2, 2018 at 4:10 PM, Dave Page <[email protected]> wrote: > Hi > > On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi < > [email protected]> wrote: > >> Hi Dave >> >> On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: >> >>> >>> >>> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >>> [email protected]> wrote: >>> >>>> Hi Dave >>>> >>>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: >>>> >>>>> Hi >>>>> >>>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Hackers, >>>>>> >>>>>> Attached is the patch to fix the RM #3397 Add support for JIT stats >>>>>> in EXPLAIN output in PG11. Please review it. >>>>>> >>>>> >>>>> A couple of immediate thoughts: >>>>> >>>>> - When the canvas is first rendered, there's a vertical scrollbar now. >>>>> As soon as I mouseover the new icon, it vanishes and the icon jumps to the >>>>> right. >>>>> >>>> >>>> Will look into it. Vertical scrollbar comes even if you remove my >>>> patch and try to hover any image. >>>> >>>>> >>>>> - The icon seems lighter than the other controls on the left. >>>>> >>>> >>>> Same css has been applied, only difference is button is disabled. >>>> >>>>> >>>>> - The icon isn't disabled when there is no info to show. >>>>> >>>> >>>> Button is always disabled, I have just change the opacity. >>>> >>>>> >>>>> Thanks. >>>>> >>>> >>> Maybe - but I can still click it and it reacts as if it's active. It may >>> be lighter to indicate that it's disabled, but its not behaving as such. >>> >> >> Attached is the modified patch. Please review it. >> > > The button still changes foreground colour on mouseover when disabled. I > think it needs to be completely non-reactive when disabled. It should also > be a noticably lighter shade when disabled; right now it seems to be darker > than the other buttons (see attached). > Attached is the modified patch. Please review it. > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [application/octet-stream] RM_3397_v3.patch (9.7K, 3-RM_3397_v3.patch) download | inline diff: diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ac463d3..226b323 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -104,6 +104,16 @@ class QueryToolFeatureTest(BaseFeatureTest): self._query_tool_notify_statements() self._clear_query_tool() + # explain query with JIT stats + print("Explain query with JIT stats... ", + file=sys.stderr, end="") + if self._supported_jit_on_server(): + self._query_tool_explain_check_jit_stats() + print("OK.", file=sys.stderr) + self._clear_query_tool() + else: + print("Skipped.", file=sys.stderr) + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -660,9 +670,62 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) + self._clear_query_tool() else: print("Skipped.", file=sys.stderr) + def _supported_jit_on_server(self): + connection = test_utils.get_db_connection( + self.server['db'], + self.server['username'], + self.server['db_password'], + self.server['host'], + self.server['port'], + self.server['sslmode'] + ) + + pg_cursor = connection.cursor() + pg_cursor.execute('select version()') + version_string = pg_cursor.fetchone() + + is_edb = False + if len(version_string) > 0: + is_edb = 'EnterpriseDB' in version_string[0] + + connection.close() + + return connection.server_version >= 110000 and not is_edb + + def _query_tool_explain_check_jit_stats(self): + wait = WebDriverWait(self.page.driver, 10) + + self.page.fill_codemirror_area_with("SET jit_above_cost=10;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self._clear_query_tool() + + self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;") + query_op = self.page.find_by_id("btn-query-dropdown") + query_op.click() + ActionChains(self.driver).move_to_element( + query_op.find_element_by_xpath( + "//li[contains(.,'Explain Options')]")).perform() + + self.page.find_by_id("btn-explain-verbose").click() + self.page.find_by_id("btn-explain-costs").click() + self.page.find_by_id("btn-explain-analyze").click() + + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Data Output') + + canvas = wait.until(EC.presence_of_element_located( + (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")) + ) + # Search for 'Output' word in result (verbose option) + canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]") + + self._clear_query_tool() + class WaitForAnyElementWithText(object): def __init__(self, locator, text): diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css index d549f85..28605df 100644 --- a/web/pgadmin/misc/static/explain/css/explain.css +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -17,6 +17,19 @@ opacity: 1; } +.pg-explain-stats-area { + position: absolute; + top: 5px; + right: 25px; +} + +.pg-explain-stats-btn { + top: 5px; + min-width: 25px; + border: 1px solid transparent; + background-color: #7777775c; +} + .explain-tooltip { display: table-cell; text-align: left; @@ -37,8 +50,6 @@ td.explain-tooltip-val { .pgadmin-explain-tooltip { position: absolute; - padding:5px; - border: 1px solid white; opacity:0; color: cornsilk; background-color: #010125; @@ -55,4 +66,10 @@ td.explain-tooltip-val { height: 100%; width: 100%; overflow: auto; -} \ No newline at end of file +} + +.pg-explain-stats-btn-disabled:hover, +.pg-explain-stats-btn-disabled:focus, +.pg-explain-stats-btn-disabled:focus { + color:#fff !important; +} diff --git a/web/pgadmin/misc/static/explain/js/explain.js b/web/pgadmin/misc/static/explain/js/explain.js index e028774..67bb531 100644 --- a/web/pgadmin/misc/static/explain/js/explain.js +++ b/web/pgadmin/misc/static/explain/js/explain.js @@ -615,6 +615,9 @@ define('pgadmin.misc.explain', [ }); toolTipContainer.css('left', toolTipX); toolTipContainer.css('top', toolTipY); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); }); // Remove tooltip when mouse is out from node's area @@ -687,6 +690,87 @@ define('pgadmin.misc.explain', [ }, }); + // Backbone model for other statistics + var StatsModel = Backbone.Model.extend({ + defaults: { + JIT: [], + Triggers: [], + }, + set_statistics: function(xpos, ypos, graphContainer, toolTipContainer) { + var jit_stats = this.get('JIT'), + triggers_stats = this.get('Triggers'); + $('.pg-explain-stats-area').on('mouseover', () => { + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + if (Object.keys(jit_stats).length == 0 && + Object.keys(triggers_stats).length == 0) { + return; + } + + $('#btn-explain-stats').removeClass('pg-explain-stats-btn-disabled'); + var tooltip = $('<table></table>', { + class: 'pgadmin-tooltip-table', + }).appendTo(toolTipContainer); + + if (Object.keys(jit_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">JIT:</td></tr>'); + _.each(jit_stats, function(value, key) { + tooltip.append('<tr><td class="label explain-tooltip">  ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + }); + } + + if (Object.keys(triggers_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">Triggers:</td></tr>'); + _.each(triggers_stats, function(triggers, key_id) { + if (triggers instanceof Object) { + _.each(triggers, function(value, key) { + if (key === 'Trigger Name') { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } + }); + } + else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key_id + '</td><td class="label explain-tooltip-val">' + + triggers + '</td></tr>'); + } + }); + } + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({ + 'opacity': '0.8', + 'left': '', + 'right': '65px', + 'top': '15px', + }); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); + }); + + // Remove tooltip when mouse is out from node's area + $('.pg-explain-stats-area').on('mouseout', () => { + $('#btn-explain-stats').addClass('pg-explain-stats-btn-disabled'); + toolTipContainer.empty(); + toolTipContainer.css({ + 'opacity': '0', + 'left': 0, + 'top': 0, + }); + }); + }, + }); + // Main backbone model to store JSON object var MainPlanModel = Backbone.Model.extend({ defaults: { @@ -696,6 +780,7 @@ define('pgadmin.misc.explain', [ }, initialize: function() { this.set('Plan', new PlanModel()); + this.set('Statistics', new StatsModel()); }, // Parse the JSON data and fetch its children plans @@ -718,6 +803,17 @@ define('pgadmin.misc.explain', [ delete data['Plan']; } + var stats = this.get('Statistics'); + if (data && 'JIT' in data) { + stats.set('JIT', data['JIT']); + delete data ['JIT']; + } + + if (data && 'Triggers' in data) { + stats.set('Triggers', data['Triggers']); + delete data ['Triggers']; + } + return data; }, toJSON: function() { @@ -745,6 +841,10 @@ define('pgadmin.misc.explain', [ plan.draw( g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer ); + + //Set the Statistics as tooltip + var stats = this.get('Statistics'); + stats.set_statistics(xpos, ypos, graphContainer, toolTipContainer); }, }); @@ -784,6 +884,22 @@ define('pgadmin.misc.explain', [ class: 'fa fa-search-minus', })); + var statsArea = $('<div></div>', { + class: 'pg-explain-stats-area btn-group', + role: 'group', + }).appendTo(container); + + $('<button></button>', { + id: 'btn-explain-stats', + class: 'btn pg-explain-stats-btn badge pg-explain-stats-btn-disabled', + title: 'Statistics', + tabindex: 0, + disabled: 'disabled', + }).appendTo(statsArea).append( + $('<i></i>', { + class: 'fa fa-line-chart', + })); + // Main div to be drawn all images on var planDiv = $('<div></div>', { class: 'pgadmin-explain-container', ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-03 13:10 Akshay Joshi <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-07-03 13:10 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi Dave, Please ignore the previous patch, I have made some more changes related to background colour on enabled/disabled state. Attached is the modified patch. Please review it. On Tue, Jul 3, 2018 at 12:35 PM, Akshay Joshi <[email protected] > wrote: > Hi Dave, > > On Mon, Jul 2, 2018 at 4:10 PM, Dave Page <[email protected]> wrote: > >> Hi >> >> On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Dave >>> >>> On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: >>> >>>> >>>> >>>> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >>>> [email protected]> wrote: >>>> >>>>> Hi Dave >>>>> >>>>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: >>>>> >>>>>> Hi >>>>>> >>>>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Hackers, >>>>>>> >>>>>>> Attached is the patch to fix the RM #3397 Add support for JIT stats >>>>>>> in EXPLAIN output in PG11. Please review it. >>>>>>> >>>>>> >>>>>> A couple of immediate thoughts: >>>>>> >>>>>> - When the canvas is first rendered, there's a vertical scrollbar >>>>>> now. As soon as I mouseover the new icon, it vanishes and the icon jumps to >>>>>> the right. >>>>>> >>>>> >>>>> Will look into it. Vertical scrollbar comes even if you remove my >>>>> patch and try to hover any image. >>>>> >>>>>> >>>>>> - The icon seems lighter than the other controls on the left. >>>>>> >>>>> >>>>> Same css has been applied, only difference is button is disabled. >>>>> >>>>>> >>>>>> - The icon isn't disabled when there is no info to show. >>>>>> >>>>> >>>>> Button is always disabled, I have just change the opacity. >>>>> >>>>>> >>>>>> Thanks. >>>>>> >>>>> >>>> Maybe - but I can still click it and it reacts as if it's active. It >>>> may be lighter to indicate that it's disabled, but its not behaving as >>>> such. >>>> >>> >>> Attached is the modified patch. Please review it. >>> >> >> The button still changes foreground colour on mouseover when disabled. I >> think it needs to be completely non-reactive when disabled. It should also >> be a noticably lighter shade when disabled; right now it seems to be darker >> than the other buttons (see attached). >> > > Attached is the modified patch. Please review it. > >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company >> > > > > -- > *Akshay Joshi* > > *Sr. Software Architect * > > > > *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [application/octet-stream] RM_3397_v4.patch (9.8K, 3-RM_3397_v4.patch) download | inline diff: diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ac463d3..226b323 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -104,6 +104,16 @@ class QueryToolFeatureTest(BaseFeatureTest): self._query_tool_notify_statements() self._clear_query_tool() + # explain query with JIT stats + print("Explain query with JIT stats... ", + file=sys.stderr, end="") + if self._supported_jit_on_server(): + self._query_tool_explain_check_jit_stats() + print("OK.", file=sys.stderr) + self._clear_query_tool() + else: + print("Skipped.", file=sys.stderr) + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -660,9 +670,62 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) + self._clear_query_tool() else: print("Skipped.", file=sys.stderr) + def _supported_jit_on_server(self): + connection = test_utils.get_db_connection( + self.server['db'], + self.server['username'], + self.server['db_password'], + self.server['host'], + self.server['port'], + self.server['sslmode'] + ) + + pg_cursor = connection.cursor() + pg_cursor.execute('select version()') + version_string = pg_cursor.fetchone() + + is_edb = False + if len(version_string) > 0: + is_edb = 'EnterpriseDB' in version_string[0] + + connection.close() + + return connection.server_version >= 110000 and not is_edb + + def _query_tool_explain_check_jit_stats(self): + wait = WebDriverWait(self.page.driver, 10) + + self.page.fill_codemirror_area_with("SET jit_above_cost=10;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self._clear_query_tool() + + self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;") + query_op = self.page.find_by_id("btn-query-dropdown") + query_op.click() + ActionChains(self.driver).move_to_element( + query_op.find_element_by_xpath( + "//li[contains(.,'Explain Options')]")).perform() + + self.page.find_by_id("btn-explain-verbose").click() + self.page.find_by_id("btn-explain-costs").click() + self.page.find_by_id("btn-explain-analyze").click() + + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Data Output') + + canvas = wait.until(EC.presence_of_element_located( + (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")) + ) + # Search for 'Output' word in result (verbose option) + canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]") + + self._clear_query_tool() + class WaitForAnyElementWithText(object): def __init__(self, locator, text): diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css index d549f85..e060f23 100644 --- a/web/pgadmin/misc/static/explain/css/explain.css +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -17,6 +17,18 @@ opacity: 1; } +.pg-explain-stats-area { + position: absolute; + top: 5px; + right: 25px; +} + +.pg-explain-stats-btn { + top: 5px; + min-width: 25px; + border: 1px solid transparent; +} + .explain-tooltip { display: table-cell; text-align: left; @@ -37,8 +49,6 @@ td.explain-tooltip-val { .pgadmin-explain-tooltip { position: absolute; - padding:5px; - border: 1px solid white; opacity:0; color: cornsilk; background-color: #010125; @@ -55,4 +65,14 @@ td.explain-tooltip-val { height: 100%; width: 100%; overflow: auto; -} \ No newline at end of file +} + +.pg-explain-stats-btn-disabled { + background-color: #7777775c; +} + +.pg-explain-stats-btn-disabled:hover, +.pg-explain-stats-btn-disabled:focus, +.pg-explain-stats-btn-disabled:focus { + color:#fff !important; +} diff --git a/web/pgadmin/misc/static/explain/js/explain.js b/web/pgadmin/misc/static/explain/js/explain.js index e028774..29ab26c 100644 --- a/web/pgadmin/misc/static/explain/js/explain.js +++ b/web/pgadmin/misc/static/explain/js/explain.js @@ -615,6 +615,9 @@ define('pgadmin.misc.explain', [ }); toolTipContainer.css('left', toolTipX); toolTipContainer.css('top', toolTipY); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); }); // Remove tooltip when mouse is out from node's area @@ -687,6 +690,91 @@ define('pgadmin.misc.explain', [ }, }); + // Backbone model for other statistics + var StatsModel = Backbone.Model.extend({ + defaults: { + JIT: [], + Triggers: [], + }, + set_statistics: function(xpos, ypos, graphContainer, toolTipContainer) { + var jit_stats = this.get('JIT'), + triggers_stats = this.get('Triggers'); + + if (Object.keys(jit_stats).length > 0 || + Object.keys(triggers_stats).length > 0) { + $('#btn-explain-stats').removeClass('pg-explain-stats-btn-disabled'); + } + + $('.pg-explain-stats-area').on('mouseover', () => { + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + if (Object.keys(jit_stats).length == 0 && + Object.keys(triggers_stats).length == 0) { + return; + } + + var tooltip = $('<table></table>', { + class: 'pgadmin-tooltip-table', + }).appendTo(toolTipContainer); + + if (Object.keys(jit_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">JIT:</td></tr>'); + _.each(jit_stats, function(value, key) { + tooltip.append('<tr><td class="label explain-tooltip">  ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + }); + } + + if (Object.keys(triggers_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">Triggers:</td></tr>'); + _.each(triggers_stats, function(triggers, key_id) { + if (triggers instanceof Object) { + _.each(triggers, function(value, key) { + if (key === 'Trigger Name') { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } + }); + } + else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key_id + '</td><td class="label explain-tooltip-val">' + + triggers + '</td></tr>'); + } + }); + } + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({ + 'opacity': '0.8', + 'left': '', + 'right': '65px', + 'top': '15px', + }); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); + }); + + // Remove tooltip when mouse is out from node's area + $('.pg-explain-stats-area').on('mouseout', () => { + toolTipContainer.empty(); + toolTipContainer.css({ + 'opacity': '0', + 'left': 0, + 'top': 0, + }); + }); + }, + }); + // Main backbone model to store JSON object var MainPlanModel = Backbone.Model.extend({ defaults: { @@ -696,6 +784,7 @@ define('pgadmin.misc.explain', [ }, initialize: function() { this.set('Plan', new PlanModel()); + this.set('Statistics', new StatsModel()); }, // Parse the JSON data and fetch its children plans @@ -718,6 +807,17 @@ define('pgadmin.misc.explain', [ delete data['Plan']; } + var stats = this.get('Statistics'); + if (data && 'JIT' in data) { + stats.set('JIT', data['JIT']); + delete data ['JIT']; + } + + if (data && 'Triggers' in data) { + stats.set('Triggers', data['Triggers']); + delete data ['Triggers']; + } + return data; }, toJSON: function() { @@ -745,6 +845,10 @@ define('pgadmin.misc.explain', [ plan.draw( g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer ); + + //Set the Statistics as tooltip + var stats = this.get('Statistics'); + stats.set_statistics(xpos, ypos, graphContainer, toolTipContainer); }, }); @@ -784,6 +888,22 @@ define('pgadmin.misc.explain', [ class: 'fa fa-search-minus', })); + var statsArea = $('<div></div>', { + class: 'pg-explain-stats-area btn-group', + role: 'group', + }).appendTo(container); + + $('<button></button>', { + id: 'btn-explain-stats', + class: 'btn pg-explain-stats-btn badge pg-explain-stats-btn-disabled', + title: 'Statistics', + tabindex: 0, + disabled: 'disabled', + }).appendTo(statsArea).append( + $('<i></i>', { + class: 'fa fa-line-chart', + })); + // Main div to be drawn all images on var planDiv = $('<div></div>', { class: 'pgadmin-explain-container', ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-05 10:21 Akshay Joshi <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-07-05 10:21 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi Dave As per discussion attached is the modified patch with following review comments has been fixed : - Hide statistics button if not applicable(no statistics to show). - Extract 'StatisticsModel' into a separate file and added jasmine test for this. On Tue, Jul 3, 2018 at 6:40 PM, Akshay Joshi <[email protected]> wrote: > Hi Dave, > > Please ignore the previous patch, I have made some more changes related to > background colour on enabled/disabled state. > Attached is the modified patch. Please review it. > > On Tue, Jul 3, 2018 at 12:35 PM, Akshay Joshi < > [email protected]> wrote: > >> Hi Dave, >> >> On Mon, Jul 2, 2018 at 4:10 PM, Dave Page <[email protected]> wrote: >> >>> Hi >>> >>> On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi < >>> [email protected]> wrote: >>> >>>> Hi Dave >>>> >>>> On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: >>>> >>>>> >>>>> >>>>> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Dave >>>>>> >>>>>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> wrote: >>>>>> >>>>>>> Hi >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Hackers, >>>>>>>> >>>>>>>> Attached is the patch to fix the RM #3397 Add support for JIT >>>>>>>> stats in EXPLAIN output in PG11. Please review it. >>>>>>>> >>>>>>> >>>>>>> A couple of immediate thoughts: >>>>>>> >>>>>>> - When the canvas is first rendered, there's a vertical scrollbar >>>>>>> now. As soon as I mouseover the new icon, it vanishes and the icon jumps to >>>>>>> the right. >>>>>>> >>>>>> >>>>>> Will look into it. Vertical scrollbar comes even if you remove >>>>>> my patch and try to hover any image. >>>>>> >>>>>>> >>>>>>> - The icon seems lighter than the other controls on the left. >>>>>>> >>>>>> >>>>>> Same css has been applied, only difference is button is >>>>>> disabled. >>>>>> >>>>>>> >>>>>>> - The icon isn't disabled when there is no info to show. >>>>>>> >>>>>> >>>>>> Button is always disabled, I have just change the opacity. >>>>>> >>>>>>> >>>>>>> Thanks. >>>>>>> >>>>>> >>>>> Maybe - but I can still click it and it reacts as if it's active. It >>>>> may be lighter to indicate that it's disabled, but its not behaving as >>>>> such. >>>>> >>>> >>>> Attached is the modified patch. Please review it. >>>> >>> >>> The button still changes foreground colour on mouseover when disabled. >>> I think it needs to be completely non-reactive when disabled. It should >>> also be a noticably lighter shade when disabled; right now it seems to be >>> darker than the other buttons (see attached). >>> >> >> Attached is the modified patch. Please review it. >> >>> >>> -- >>> Dave Page >>> Blog: http://pgsnake.blogspot.com >>> Twitter: @pgsnake >>> >>> EnterpriseDB UK: http://www.enterprisedb.com >>> The Enterprise PostgreSQL Company >>> >> >> >> >> -- >> *Akshay Joshi* >> >> *Sr. Software Architect * >> >> >> >> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >> > > > > -- > *Akshay Joshi* > > *Sr. Software Architect * > > > > *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [application/octet-stream] RM_3397_v5.patch (12.9K, 3-RM_3397_v5.patch) download | inline diff: diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ac463d3..226b323 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -104,6 +104,16 @@ class QueryToolFeatureTest(BaseFeatureTest): self._query_tool_notify_statements() self._clear_query_tool() + # explain query with JIT stats + print("Explain query with JIT stats... ", + file=sys.stderr, end="") + if self._supported_jit_on_server(): + self._query_tool_explain_check_jit_stats() + print("OK.", file=sys.stderr) + self._clear_query_tool() + else: + print("Skipped.", file=sys.stderr) + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -660,9 +670,62 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) + self._clear_query_tool() else: print("Skipped.", file=sys.stderr) + def _supported_jit_on_server(self): + connection = test_utils.get_db_connection( + self.server['db'], + self.server['username'], + self.server['db_password'], + self.server['host'], + self.server['port'], + self.server['sslmode'] + ) + + pg_cursor = connection.cursor() + pg_cursor.execute('select version()') + version_string = pg_cursor.fetchone() + + is_edb = False + if len(version_string) > 0: + is_edb = 'EnterpriseDB' in version_string[0] + + connection.close() + + return connection.server_version >= 110000 and not is_edb + + def _query_tool_explain_check_jit_stats(self): + wait = WebDriverWait(self.page.driver, 10) + + self.page.fill_codemirror_area_with("SET jit_above_cost=10;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self._clear_query_tool() + + self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;") + query_op = self.page.find_by_id("btn-query-dropdown") + query_op.click() + ActionChains(self.driver).move_to_element( + query_op.find_element_by_xpath( + "//li[contains(.,'Explain Options')]")).perform() + + self.page.find_by_id("btn-explain-verbose").click() + self.page.find_by_id("btn-explain-costs").click() + self.page.find_by_id("btn-explain-analyze").click() + + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Data Output') + + canvas = wait.until(EC.presence_of_element_located( + (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")) + ) + # Search for 'Output' word in result (verbose option) + canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]") + + self._clear_query_tool() + class WaitForAnyElementWithText(object): def __init__(self, locator, text): diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css index d549f85..d0a4409 100644 --- a/web/pgadmin/misc/static/explain/css/explain.css +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -17,6 +17,19 @@ opacity: 1; } +.pg-explain-stats-area { + position: absolute; + top: 5px; + right: 25px; + opacity: 0.5; +} + +.pg-explain-stats-btn { + top: 5px; + min-width: 25px; + border: 1px solid transparent; +} + .explain-tooltip { display: table-cell; text-align: left; @@ -37,8 +50,6 @@ td.explain-tooltip-val { .pgadmin-explain-tooltip { position: absolute; - padding:5px; - border: 1px solid white; opacity:0; color: cornsilk; background-color: #010125; @@ -55,4 +66,4 @@ td.explain-tooltip-val { height: 100%; width: 100%; overflow: auto; -} \ No newline at end of file +} diff --git a/web/pgadmin/misc/static/explain/js/explain.js b/web/pgadmin/misc/static/explain/js/explain.js index e028774..341ca99 100644 --- a/web/pgadmin/misc/static/explain/js/explain.js +++ b/web/pgadmin/misc/static/explain/js/explain.js @@ -1,7 +1,7 @@ define('pgadmin.misc.explain', [ 'sources/url_for', 'jquery', 'underscore', 'underscore.string', - 'sources/pgadmin', 'backbone', 'snapsvg', -], function(url_for, $, _, S, pgAdmin, Backbone, Snap) { + 'sources/pgadmin', 'backbone', 'snapsvg', 'explain_statistics', +], function(url_for, $, _, S, pgAdmin, Backbone, Snap, StatisticsModel) { pgAdmin = pgAdmin || window.pgAdmin || {}; @@ -615,6 +615,9 @@ define('pgadmin.misc.explain', [ }); toolTipContainer.css('left', toolTipX); toolTipContainer.css('top', toolTipY); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); }); // Remove tooltip when mouse is out from node's area @@ -696,6 +699,7 @@ define('pgadmin.misc.explain', [ }, initialize: function() { this.set('Plan', new PlanModel()); + this.set('Statistics', new StatisticsModel()); }, // Parse the JSON data and fetch its children plans @@ -718,6 +722,17 @@ define('pgadmin.misc.explain', [ delete data['Plan']; } + var statistics = this.get('Statistics'); + if (data && 'JIT' in data) { + statistics.set('JIT', data['JIT']); + delete data ['JIT']; + } + + if (data && 'Triggers' in data) { + statistics.set('Triggers', data['Triggers']); + delete data ['Triggers']; + } + return data; }, toJSON: function() { @@ -745,6 +760,10 @@ define('pgadmin.misc.explain', [ plan.draw( g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer ); + + //Set the Statistics as tooltip + var statistics = this.get('Statistics'); + statistics.set_statistics(toolTipContainer); }, }); @@ -784,6 +803,22 @@ define('pgadmin.misc.explain', [ class: 'fa fa-search-minus', })); + var statsArea = $('<div></div>', { + class: 'pg-explain-stats-area btn-group hidden', + role: 'group', + }).appendTo(container); + + $('<button></button>', { + id: 'btn-explain-stats', + class: 'btn pg-explain-stats-btn badge', + title: 'Statistics', + tabindex: 0, + disabled: 'disabled', + }).appendTo(statsArea).append( + $('<i></i>', { + class: 'fa fa-line-chart', + })); + // Main div to be drawn all images on var planDiv = $('<div></div>', { class: 'pgadmin-explain-container', diff --git a/web/pgadmin/misc/static/explain/js/explain_statistics.js b/web/pgadmin/misc/static/explain/js/explain_statistics.js new file mode 100644 index 0000000..369a671 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/explain_statistics.js @@ -0,0 +1,90 @@ +import $ from 'jquery'; +import Backbone from 'backbone'; + +// Backbone model for other statistics +let StatisticsModel = Backbone.Model.extend({ + defaults: { + JIT: [], + Triggers: [], + }, + + set_statistics: function(toolTipContainer) { + var jit_stats = this.get('JIT'), + triggers_stats = this.get('Triggers'); + + if (Object.keys(jit_stats).length > 0 || + Object.keys(triggers_stats).length > 0) { + $('.pg-explain-stats-area').removeClass('hidden'); + } + + $('.pg-explain-stats-area').on('mouseover', () => { + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + if (Object.keys(jit_stats).length == 0 && + Object.keys(triggers_stats).length == 0) { + return; + } + + var tooltip = $('<table></table>', { + class: 'pgadmin-tooltip-table', + }).appendTo(toolTipContainer); + + if (Object.keys(jit_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">JIT:</td></tr>'); + _.each(jit_stats, function(value, key) { + tooltip.append('<tr><td class="label explain-tooltip">  ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + }); + } + + if (Object.keys(triggers_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">Triggers:</td></tr>'); + _.each(triggers_stats, function(triggers, key_id) { + if (triggers instanceof Object) { + _.each(triggers, function(value, key) { + if (key === 'Trigger Name') { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } + }); + } + else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key_id + '</td><td class="label explain-tooltip-val">' + + triggers + '</td></tr>'); + } + }); + } + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({ + 'opacity': '0.8', + 'left': '', + 'right': '65px', + 'top': '15px', + }); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); + }); + + // Remove tooltip when mouse is out from node's area + $('.pg-explain-stats-area').on('mouseout', () => { + toolTipContainer.empty(); + toolTipContainer.css({ + 'opacity': '0', + 'left': 0, + 'top': 0, + }); + }); + }, +}); + +module.exports = StatisticsModel; diff --git a/web/regression/javascript/misc/explain/explain_statistics_spec.js b/web/regression/javascript/misc/explain/explain_statistics_spec.js new file mode 100644 index 0000000..0b2ec67 --- /dev/null +++ b/web/regression/javascript/misc/explain/explain_statistics_spec.js @@ -0,0 +1,87 @@ +import StatisticsModel from '../../../../pgadmin/misc/static/explain/js/explain_statistics'; +import $ from 'jquery'; + +describe('ExplainStatistics', () => { + let statsModel; + let statsDiv; + let tooltipContainer; + + beforeEach(function() { + statsModel = new StatisticsModel(); + statsDiv = '<div class="pg-explain-stats-area btn-group hidden"></div>'; + tooltipContainer = $('<div></div>', { + id: 'toolTip', + class: 'pgadmin-explain-tooltip', + }); + }); + + describe('No Statistics', () => { + it('Statistics button should be hidden', () => { + $('body').append(statsDiv); + + statsModel.set('JIT', []); + statsModel.set('Triggers', []); + statsModel.set_statistics(tooltipContainer); + + expect($('.pg-explain-stats-area').hasClass('hidden')).toBe(true); + }); + }); + + describe('JIT Statistics', () => { + beforeEach(function() { + $('body').append(statsDiv); + statsModel.set('JIT', [{'cost': '100'}]); + statsModel.set('Triggers', []); + statsModel.set_statistics(tooltipContainer); + }); + + it('Statistics button should be visible', () => { + expect($('.pg-explain-stats-area').hasClass('hidden')).toBe(false); + }); + + it('Mouse over event should be trigger', () => { + // Trigger mouse over event + var hoverEvent = new $.Event('mouseover'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0.8'); + }); + + it('Mouse out event should be trigger', () => { + // Trigger mouse out event + var hoverEvent = new $.Event('mouseout'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0'); + }); + }); + + describe('Triggers Statistics', () => { + beforeEach(function() { + $('body').append(statsDiv); + statsModel.set('JIT', []); + statsModel.set('Triggers', [{'name': 'test_trigger'}]); + statsModel.set_statistics(tooltipContainer); + }); + + it('Statistics button should be visible', () => { + expect($('.pg-explain-stats-area').hasClass('hidden')).toBe(false); + }); + + it('Mouse over event should be trigger', () => { + // Trigger mouse over event + var hoverEvent = new $.Event('mouseover'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0.8'); + }); + + it('Mouse out event should be trigger', () => { + // Trigger mouse out event + var hoverEvent = new $.Event('mouseout'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0'); + }); + }); +}); ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-05 13:47 Dave Page <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Dave Page @ 2018-07-05 13:47 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi Looks good to me - the only remaining issue is that the button still isn't the same colours as the zoom ones. I haven't found all the differences, but there seems to be an 'opacity: 0.5" on the stats area, and the disabled attribute is still being set. On Thu, Jul 5, 2018 at 11:21 AM, Akshay Joshi <[email protected] > wrote: > Hi Dave > > As per discussion attached is the modified patch with following review > comments has been fixed : > > - Hide statistics button if not applicable(no statistics to show). > - Extract 'StatisticsModel' into a separate file and added jasmine > test for this. > > > > > On Tue, Jul 3, 2018 at 6:40 PM, Akshay Joshi < > [email protected]> wrote: > >> Hi Dave, >> >> Please ignore the previous patch, I have made some more changes related >> to background colour on enabled/disabled state. >> Attached is the modified patch. Please review it. >> >> On Tue, Jul 3, 2018 at 12:35 PM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Dave, >>> >>> On Mon, Jul 2, 2018 at 4:10 PM, Dave Page <[email protected]> wrote: >>> >>>> Hi >>>> >>>> On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi < >>>> [email protected]> wrote: >>>> >>>>> Hi Dave >>>>> >>>>> On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: >>>>> >>>>>> >>>>>> >>>>>> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Dave >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> >>>>>>> wrote: >>>>>>> >>>>>>>> Hi >>>>>>>> >>>>>>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Hackers, >>>>>>>>> >>>>>>>>> Attached is the patch to fix the RM #3397 Add support for JIT >>>>>>>>> stats in EXPLAIN output in PG11. Please review it. >>>>>>>>> >>>>>>>> >>>>>>>> A couple of immediate thoughts: >>>>>>>> >>>>>>>> - When the canvas is first rendered, there's a vertical scrollbar >>>>>>>> now. As soon as I mouseover the new icon, it vanishes and the icon jumps to >>>>>>>> the right. >>>>>>>> >>>>>>> >>>>>>> Will look into it. Vertical scrollbar comes even if you remove >>>>>>> my patch and try to hover any image. >>>>>>> >>>>>>>> >>>>>>>> - The icon seems lighter than the other controls on the left. >>>>>>>> >>>>>>> >>>>>>> Same css has been applied, only difference is button is >>>>>>> disabled. >>>>>>> >>>>>>>> >>>>>>>> - The icon isn't disabled when there is no info to show. >>>>>>>> >>>>>>> >>>>>>> Button is always disabled, I have just change the opacity. >>>>>>> >>>>>>>> >>>>>>>> Thanks. >>>>>>>> >>>>>>> >>>>>> Maybe - but I can still click it and it reacts as if it's active. It >>>>>> may be lighter to indicate that it's disabled, but its not behaving as >>>>>> such. >>>>>> >>>>> >>>>> Attached is the modified patch. Please review it. >>>>> >>>> >>>> The button still changes foreground colour on mouseover when disabled. >>>> I think it needs to be completely non-reactive when disabled. It should >>>> also be a noticably lighter shade when disabled; right now it seems to be >>>> darker than the other buttons (see attached). >>>> >>> >>> Attached is the modified patch. Please review it. >>> >>>> >>>> -- >>>> Dave Page >>>> Blog: http://pgsnake.blogspot.com >>>> Twitter: @pgsnake >>>> >>>> EnterpriseDB UK: http://www.enterprisedb.com >>>> The Enterprise PostgreSQL Company >>>> >>> >>> >>> >>> -- >>> *Akshay Joshi* >>> >>> *Sr. Software Architect * >>> >>> >>> >>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>> >> >> >> >> -- >> *Akshay Joshi* >> >> *Sr. Software Architect * >> >> >> >> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >> > > > > -- > *Akshay Joshi* > > *Sr. Software Architect * > > > > *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-06 05:44 Akshay Joshi <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 12+ messages in thread From: Akshay Joshi @ 2018-07-06 05:44 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: pgadmin-hackers Hi On Thu, Jul 5, 2018 at 7:17 PM, Dave Page <[email protected]> wrote: > Hi > > Looks good to me - the only remaining issue is that the button still isn't > the same colours as the zoom ones. I haven't found all the differences, but > there seems to be an 'opacity: 0.5" on the stats area, and the disabled > attribute is still being set. > I have set the disabled attribute, so that the button shouldn't be clickable and because of that there is difference in colour. 'opacity: 0.5' is also there for zoom area. I have fixed the issue by removing disabled attribute and add ' *pointer-events: none*' for the statistics button. Attached is the patch please review it. > > On Thu, Jul 5, 2018 at 11:21 AM, Akshay Joshi < > [email protected]> wrote: > >> Hi Dave >> >> As per discussion attached is the modified patch with following review >> comments has been fixed : >> >> - Hide statistics button if not applicable(no statistics to show). >> - Extract 'StatisticsModel' into a separate file and added jasmine >> test for this. >> >> >> >> >> On Tue, Jul 3, 2018 at 6:40 PM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Dave, >>> >>> Please ignore the previous patch, I have made some more changes related >>> to background colour on enabled/disabled state. >>> Attached is the modified patch. Please review it. >>> >>> On Tue, Jul 3, 2018 at 12:35 PM, Akshay Joshi < >>> [email protected]> wrote: >>> >>>> Hi Dave, >>>> >>>> On Mon, Jul 2, 2018 at 4:10 PM, Dave Page <[email protected]> wrote: >>>> >>>>> Hi >>>>> >>>>> On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Dave >>>>>> >>>>>> On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> wrote: >>>>>> >>>>>>> >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Dave >>>>>>>> >>>>>>>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Hi >>>>>>>>> >>>>>>>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>>>>>>> [email protected]> wrote: >>>>>>>>> >>>>>>>>>> Hi Hackers, >>>>>>>>>> >>>>>>>>>> Attached is the patch to fix the RM #3397 Add support for JIT >>>>>>>>>> stats in EXPLAIN output in PG11. Please review it. >>>>>>>>>> >>>>>>>>> >>>>>>>>> A couple of immediate thoughts: >>>>>>>>> >>>>>>>>> - When the canvas is first rendered, there's a vertical scrollbar >>>>>>>>> now. As soon as I mouseover the new icon, it vanishes and the icon jumps to >>>>>>>>> the right. >>>>>>>>> >>>>>>>> >>>>>>>> Will look into it. Vertical scrollbar comes even if you remove >>>>>>>> my patch and try to hover any image. >>>>>>>> >>>>>>>>> >>>>>>>>> - The icon seems lighter than the other controls on the left. >>>>>>>>> >>>>>>>> >>>>>>>> Same css has been applied, only difference is button is >>>>>>>> disabled. >>>>>>>> >>>>>>>>> >>>>>>>>> - The icon isn't disabled when there is no info to show. >>>>>>>>> >>>>>>>> >>>>>>>> Button is always disabled, I have just change the opacity. >>>>>>>> >>>>>>>>> >>>>>>>>> Thanks. >>>>>>>>> >>>>>>>> >>>>>>> Maybe - but I can still click it and it reacts as if it's active. It >>>>>>> may be lighter to indicate that it's disabled, but its not behaving as >>>>>>> such. >>>>>>> >>>>>> >>>>>> Attached is the modified patch. Please review it. >>>>>> >>>>> >>>>> The button still changes foreground colour on mouseover when >>>>> disabled. I think it needs to be completely non-reactive when disabled. It >>>>> should also be a noticably lighter shade when disabled; right now it seems >>>>> to be darker than the other buttons (see attached). >>>>> >>>> >>>> Attached is the modified patch. Please review it. >>>> >>>>> >>>>> -- >>>>> Dave Page >>>>> Blog: http://pgsnake.blogspot.com >>>>> Twitter: @pgsnake >>>>> >>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>> The Enterprise PostgreSQL Company >>>>> >>>> >>>> >>>> >>>> -- >>>> *Akshay Joshi* >>>> >>>> *Sr. Software Architect * >>>> >>>> >>>> >>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>> >>> >>> >>> >>> -- >>> *Akshay Joshi* >>> >>> *Sr. Software Architect * >>> >>> >>> >>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>> >> >> >> >> -- >> *Akshay Joshi* >> >> *Sr. Software Architect * >> >> >> >> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >> > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [application/octet-stream] RM_3397_v6.patch (12.9K, 3-RM_3397_v6.patch) download | inline diff: diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ac463d3..226b323 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -104,6 +104,16 @@ class QueryToolFeatureTest(BaseFeatureTest): self._query_tool_notify_statements() self._clear_query_tool() + # explain query with JIT stats + print("Explain query with JIT stats... ", + file=sys.stderr, end="") + if self._supported_jit_on_server(): + self._query_tool_explain_check_jit_stats() + print("OK.", file=sys.stderr) + self._clear_query_tool() + else: + print("Skipped.", file=sys.stderr) + def after(self): self.page.remove_server(self.server) connection = test_utils.get_db_connection( @@ -660,9 +670,62 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) + self._clear_query_tool() else: print("Skipped.", file=sys.stderr) + def _supported_jit_on_server(self): + connection = test_utils.get_db_connection( + self.server['db'], + self.server['username'], + self.server['db_password'], + self.server['host'], + self.server['port'], + self.server['sslmode'] + ) + + pg_cursor = connection.cursor() + pg_cursor.execute('select version()') + version_string = pg_cursor.fetchone() + + is_edb = False + if len(version_string) > 0: + is_edb = 'EnterpriseDB' in version_string[0] + + connection.close() + + return connection.server_version >= 110000 and not is_edb + + def _query_tool_explain_check_jit_stats(self): + wait = WebDriverWait(self.page.driver, 10) + + self.page.fill_codemirror_area_with("SET jit_above_cost=10;") + self.page.find_by_id("btn-flash").click() + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self._clear_query_tool() + + self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;") + query_op = self.page.find_by_id("btn-query-dropdown") + query_op.click() + ActionChains(self.driver).move_to_element( + query_op.find_element_by_xpath( + "//li[contains(.,'Explain Options')]")).perform() + + self.page.find_by_id("btn-explain-verbose").click() + self.page.find_by_id("btn-explain-costs").click() + self.page.find_by_id("btn-explain-analyze").click() + + self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.click_tab('Data Output') + + canvas = wait.until(EC.presence_of_element_located( + (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")) + ) + # Search for 'Output' word in result (verbose option) + canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]") + + self._clear_query_tool() + class WaitForAnyElementWithText(object): def __init__(self, locator, text): diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css index d549f85..98a0775 100644 --- a/web/pgadmin/misc/static/explain/css/explain.css +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -17,6 +17,24 @@ opacity: 1; } +.pg-explain-stats-area { + position: absolute; + top: 5px; + right: 25px; + opacity: 0.5; +} + +.pg-explain-stats-btn { + top: 5px; + min-width: 25px; + border: 1px solid transparent; + pointer-events: none; +} + +.pg-explain-stats-area:hover { + opacity: 1; +} + .explain-tooltip { display: table-cell; text-align: left; @@ -37,8 +55,6 @@ td.explain-tooltip-val { .pgadmin-explain-tooltip { position: absolute; - padding:5px; - border: 1px solid white; opacity:0; color: cornsilk; background-color: #010125; @@ -55,4 +71,4 @@ td.explain-tooltip-val { height: 100%; width: 100%; overflow: auto; -} \ No newline at end of file +} diff --git a/web/pgadmin/misc/static/explain/js/explain.js b/web/pgadmin/misc/static/explain/js/explain.js index e028774..e27d810 100644 --- a/web/pgadmin/misc/static/explain/js/explain.js +++ b/web/pgadmin/misc/static/explain/js/explain.js @@ -1,7 +1,7 @@ define('pgadmin.misc.explain', [ 'sources/url_for', 'jquery', 'underscore', 'underscore.string', - 'sources/pgadmin', 'backbone', 'snapsvg', -], function(url_for, $, _, S, pgAdmin, Backbone, Snap) { + 'sources/pgadmin', 'backbone', 'snapsvg', 'explain_statistics', +], function(url_for, $, _, S, pgAdmin, Backbone, Snap, StatisticsModel) { pgAdmin = pgAdmin || window.pgAdmin || {}; @@ -615,6 +615,9 @@ define('pgadmin.misc.explain', [ }); toolTipContainer.css('left', toolTipX); toolTipContainer.css('top', toolTipY); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); }); // Remove tooltip when mouse is out from node's area @@ -696,6 +699,7 @@ define('pgadmin.misc.explain', [ }, initialize: function() { this.set('Plan', new PlanModel()); + this.set('Statistics', new StatisticsModel()); }, // Parse the JSON data and fetch its children plans @@ -718,6 +722,17 @@ define('pgadmin.misc.explain', [ delete data['Plan']; } + var statistics = this.get('Statistics'); + if (data && 'JIT' in data) { + statistics.set('JIT', data['JIT']); + delete data ['JIT']; + } + + if (data && 'Triggers' in data) { + statistics.set('Triggers', data['Triggers']); + delete data ['Triggers']; + } + return data; }, toJSON: function() { @@ -745,6 +760,10 @@ define('pgadmin.misc.explain', [ plan.draw( g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer ); + + //Set the Statistics as tooltip + var statistics = this.get('Statistics'); + statistics.set_statistics(toolTipContainer); }, }); @@ -784,6 +803,21 @@ define('pgadmin.misc.explain', [ class: 'fa fa-search-minus', })); + var statsArea = $('<div></div>', { + class: 'pg-explain-stats-area btn-group hidden', + role: 'group', + }).appendTo(container); + + $('<button></button>', { + id: 'btn-explain-stats', + class: 'btn pg-explain-stats-btn badge', + title: 'Statistics', + tabindex: 0, + }).appendTo(statsArea).append( + $('<i></i>', { + class: 'fa fa-line-chart', + })); + // Main div to be drawn all images on var planDiv = $('<div></div>', { class: 'pgadmin-explain-container', diff --git a/web/pgadmin/misc/static/explain/js/explain_statistics.js b/web/pgadmin/misc/static/explain/js/explain_statistics.js new file mode 100644 index 0000000..369a671 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/explain_statistics.js @@ -0,0 +1,90 @@ +import $ from 'jquery'; +import Backbone from 'backbone'; + +// Backbone model for other statistics +let StatisticsModel = Backbone.Model.extend({ + defaults: { + JIT: [], + Triggers: [], + }, + + set_statistics: function(toolTipContainer) { + var jit_stats = this.get('JIT'), + triggers_stats = this.get('Triggers'); + + if (Object.keys(jit_stats).length > 0 || + Object.keys(triggers_stats).length > 0) { + $('.pg-explain-stats-area').removeClass('hidden'); + } + + $('.pg-explain-stats-area').on('mouseover', () => { + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + if (Object.keys(jit_stats).length == 0 && + Object.keys(triggers_stats).length == 0) { + return; + } + + var tooltip = $('<table></table>', { + class: 'pgadmin-tooltip-table', + }).appendTo(toolTipContainer); + + if (Object.keys(jit_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">JIT:</td></tr>'); + _.each(jit_stats, function(value, key) { + tooltip.append('<tr><td class="label explain-tooltip">  ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + }); + } + + if (Object.keys(triggers_stats).length > 0){ + tooltip.append('<tr><td class="label explain-tooltip">Triggers:</td></tr>'); + _.each(triggers_stats, function(triggers, key_id) { + if (triggers instanceof Object) { + _.each(triggers, function(value, key) { + if (key === 'Trigger Name') { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key + '</td><td class="label explain-tooltip-val">' + + value + '</td></tr>'); + } + }); + } + else { + tooltip.append('<tr><td class="label explain-tooltip"> ' + + key_id + '</td><td class="label explain-tooltip-val">' + + triggers + '</td></tr>'); + } + }); + } + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({ + 'opacity': '0.8', + 'left': '', + 'right': '65px', + 'top': '15px', + }); + + $('.pgadmin-explain-tooltip').css('padding', '5px'); + $('.pgadmin-explain-tooltip').css('border', '1px solid white'); + }); + + // Remove tooltip when mouse is out from node's area + $('.pg-explain-stats-area').on('mouseout', () => { + toolTipContainer.empty(); + toolTipContainer.css({ + 'opacity': '0', + 'left': 0, + 'top': 0, + }); + }); + }, +}); + +module.exports = StatisticsModel; diff --git a/web/regression/javascript/misc/explain/explain_statistics_spec.js b/web/regression/javascript/misc/explain/explain_statistics_spec.js new file mode 100644 index 0000000..0b2ec67 --- /dev/null +++ b/web/regression/javascript/misc/explain/explain_statistics_spec.js @@ -0,0 +1,87 @@ +import StatisticsModel from '../../../../pgadmin/misc/static/explain/js/explain_statistics'; +import $ from 'jquery'; + +describe('ExplainStatistics', () => { + let statsModel; + let statsDiv; + let tooltipContainer; + + beforeEach(function() { + statsModel = new StatisticsModel(); + statsDiv = '<div class="pg-explain-stats-area btn-group hidden"></div>'; + tooltipContainer = $('<div></div>', { + id: 'toolTip', + class: 'pgadmin-explain-tooltip', + }); + }); + + describe('No Statistics', () => { + it('Statistics button should be hidden', () => { + $('body').append(statsDiv); + + statsModel.set('JIT', []); + statsModel.set('Triggers', []); + statsModel.set_statistics(tooltipContainer); + + expect($('.pg-explain-stats-area').hasClass('hidden')).toBe(true); + }); + }); + + describe('JIT Statistics', () => { + beforeEach(function() { + $('body').append(statsDiv); + statsModel.set('JIT', [{'cost': '100'}]); + statsModel.set('Triggers', []); + statsModel.set_statistics(tooltipContainer); + }); + + it('Statistics button should be visible', () => { + expect($('.pg-explain-stats-area').hasClass('hidden')).toBe(false); + }); + + it('Mouse over event should be trigger', () => { + // Trigger mouse over event + var hoverEvent = new $.Event('mouseover'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0.8'); + }); + + it('Mouse out event should be trigger', () => { + // Trigger mouse out event + var hoverEvent = new $.Event('mouseout'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0'); + }); + }); + + describe('Triggers Statistics', () => { + beforeEach(function() { + $('body').append(statsDiv); + statsModel.set('JIT', []); + statsModel.set('Triggers', [{'name': 'test_trigger'}]); + statsModel.set_statistics(tooltipContainer); + }); + + it('Statistics button should be visible', () => { + expect($('.pg-explain-stats-area').hasClass('hidden')).toBe(false); + }); + + it('Mouse over event should be trigger', () => { + // Trigger mouse over event + var hoverEvent = new $.Event('mouseover'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0.8'); + }); + + it('Mouse out event should be trigger', () => { + // Trigger mouse out event + var hoverEvent = new $.Event('mouseout'); + $('.pg-explain-stats-area').trigger(hoverEvent); + + expect(tooltipContainer.css('opacity')).toBe('0'); + }); + }); +}); ^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 @ 2018-07-06 12:14 Dave Page <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 0 replies; 12+ messages in thread From: Dave Page @ 2018-07-06 12:14 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Thanks, patch applied! On Fri, Jul 6, 2018 at 6:44 AM, Akshay Joshi <[email protected]> wrote: > Hi > > On Thu, Jul 5, 2018 at 7:17 PM, Dave Page <[email protected]> wrote: > >> Hi >> >> Looks good to me - the only remaining issue is that the button still >> isn't the same colours as the zoom ones. I haven't found all the >> differences, but there seems to be an 'opacity: 0.5" on the stats area, and >> the disabled attribute is still being set. >> > > I have set the disabled attribute, so that the button shouldn't be > clickable and because of that there is difference in colour. 'opacity: > 0.5' is also there for zoom area. I have fixed the issue by removing > disabled attribute and add ' > > *pointer-events: none*' for the statistics button. Attached is the patch > please review it. > >> >> On Thu, Jul 5, 2018 at 11:21 AM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Dave >>> >>> As per discussion attached is the modified patch with following review >>> comments has been fixed : >>> >>> - Hide statistics button if not applicable(no statistics to show). >>> - Extract 'StatisticsModel' into a separate file and added jasmine >>> test for this. >>> >>> >>> >>> >>> On Tue, Jul 3, 2018 at 6:40 PM, Akshay Joshi < >>> [email protected]> wrote: >>> >>>> Hi Dave, >>>> >>>> Please ignore the previous patch, I have made some more changes related >>>> to background colour on enabled/disabled state. >>>> Attached is the modified patch. Please review it. >>>> >>>> On Tue, Jul 3, 2018 at 12:35 PM, Akshay Joshi < >>>> [email protected]> wrote: >>>> >>>>> Hi Dave, >>>>> >>>>> On Mon, Jul 2, 2018 at 4:10 PM, Dave Page <[email protected]> wrote: >>>>> >>>>>> Hi >>>>>> >>>>>> On Sat, Jun 30, 2018 at 9:15 AM, Akshay Joshi < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Dave >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 7:45 PM, Dave Page <[email protected]> >>>>>>> wrote: >>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> On Fri, Jun 29, 2018 at 3:12 PM, Akshay Joshi < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Dave >>>>>>>>> >>>>>>>>> On Fri, Jun 29, 2018 at 6:56 PM, Dave Page <[email protected]> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> Hi >>>>>>>>>> >>>>>>>>>> On Fri, Jun 29, 2018 at 9:55 AM, Akshay Joshi < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> Hi Hackers, >>>>>>>>>>> >>>>>>>>>>> Attached is the patch to fix the RM #3397 Add support for JIT >>>>>>>>>>> stats in EXPLAIN output in PG11. Please review it. >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> A couple of immediate thoughts: >>>>>>>>>> >>>>>>>>>> - When the canvas is first rendered, there's a vertical scrollbar >>>>>>>>>> now. As soon as I mouseover the new icon, it vanishes and the icon jumps to >>>>>>>>>> the right. >>>>>>>>>> >>>>>>>>> >>>>>>>>> Will look into it. Vertical scrollbar comes even if you >>>>>>>>> remove my patch and try to hover any image. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> - The icon seems lighter than the other controls on the left. >>>>>>>>>> >>>>>>>>> >>>>>>>>> Same css has been applied, only difference is button is >>>>>>>>> disabled. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> - The icon isn't disabled when there is no info to show. >>>>>>>>>> >>>>>>>>> >>>>>>>>> Button is always disabled, I have just change the opacity. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> Thanks. >>>>>>>>>> >>>>>>>>> >>>>>>>> Maybe - but I can still click it and it reacts as if it's active. >>>>>>>> It may be lighter to indicate that it's disabled, but its not behaving as >>>>>>>> such. >>>>>>>> >>>>>>> >>>>>>> Attached is the modified patch. Please review it. >>>>>>> >>>>>> >>>>>> The button still changes foreground colour on mouseover when >>>>>> disabled. I think it needs to be completely non-reactive when disabled. It >>>>>> should also be a noticably lighter shade when disabled; right now it seems >>>>>> to be darker than the other buttons (see attached). >>>>>> >>>>> >>>>> Attached is the modified patch. Please review it. >>>>> >>>>>> >>>>>> -- >>>>>> Dave Page >>>>>> Blog: http://pgsnake.blogspot.com >>>>>> Twitter: @pgsnake >>>>>> >>>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>>> The Enterprise PostgreSQL Company >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> *Akshay Joshi* >>>>> >>>>> *Sr. Software Architect * >>>>> >>>>> >>>>> >>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>> >>>> >>>> >>>> >>>> -- >>>> *Akshay Joshi* >>>> >>>> *Sr. Software Architect * >>>> >>>> >>>> >>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>> >>> >>> >>> >>> -- >>> *Akshay Joshi* >>> >>> *Sr. Software Architect * >>> >>> >>> >>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>> >> >> >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company >> > > > > -- > *Akshay Joshi* > > *Sr. Software Architect * > > > > *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 12+ messages in thread
end of thread, other threads:[~2018-07-06 12:14 UTC | newest] Thread overview: 12+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2018-06-29 08:55 [pgAdmin4][Patch]: RM #3397 Add support for JIT stats in EXPLAIN output in PG11 Akshay Joshi <[email protected]> 2018-06-29 13:26 ` Dave Page <[email protected]> 2018-06-29 14:12 ` Akshay Joshi <[email protected]> 2018-06-29 14:15 ` Dave Page <[email protected]> 2018-06-30 08:15 ` Akshay Joshi <[email protected]> 2018-07-02 10:40 ` Dave Page <[email protected]> 2018-07-03 07:05 ` Akshay Joshi <[email protected]> 2018-07-03 13:10 ` Akshay Joshi <[email protected]> 2018-07-05 10:21 ` Akshay Joshi <[email protected]> 2018-07-05 13:47 ` Dave Page <[email protected]> 2018-07-06 05:44 ` Akshay Joshi <[email protected]> 2018-07-06 12:14 ` Dave Page <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox