IGNITE-4821 Implemented enforce join order option on query tab.

Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/94c1e7cb
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/94c1e7cb
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/94c1e7cb

Branch: refs/heads/ignite-1192
Commit: 94c1e7cb505e0a40e1d3c28de5a25b5aefbd55c0
Parents: f361da4
Author: Vasiliy Sisko <vsi...@gridgain.com>
Authored: Wed Mar 15 11:43:23 2017 +0700
Committer: Andrey Novikov <anovi...@gridgain.com>
Committed: Wed Mar 15 11:43:23 2017 +0700

----------------------------------------------------------------------
 modules/web-console/backend/app/agent.js        | 14 ++++++-
 modules/web-console/backend/app/browser.js      |  8 ++--
 .../frontend/app/modules/agent/agent.module.js  | 10 +++--
 .../frontend/app/modules/sql/sql.controller.js  | 25 ++++++++++---
 .../frontend/public/stylesheets/style.scss      |  8 +++-
 .../web-console/frontend/views/sql/sql.tpl.pug  | 39 +++++++++++++-------
 6 files changed, 74 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/backend/app/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/agent.js 
b/modules/web-console/backend/app/agent.js
index b4394b7..f65eabb 100644
--- a/modules/web-console/backend/app/agent.js
+++ b/modules/web-console/backend/app/agent.js
@@ -227,17 +227,27 @@ module.exports.factory = function(_, fs, path, JSZip, 
socketio, settings, mongo,
          * @param {String} cacheName Cache name.
          * @param {String} query Query.
          * @param {Boolean} nonCollocatedJoins Flag whether to execute non 
collocated joins.
+         * @param {Boolean} enforceJoinOrder Flag whether enforce join order 
is enabled.
          * @param {Boolean} local Flag whether to execute query locally.
          * @param {int} pageSize Page size.
          * @returns {Promise}
          */
-        fieldsQuery(demo, nid, cacheName, query, nonCollocatedJoins, local, 
pageSize) {
+        fieldsQuery(demo, nid, cacheName, query, nonCollocatedJoins, 
enforceJoinOrder, local, pageSize) {
             const cmd = new Command(demo, 'exe')
                 .addParam('name', 
'org.apache.ignite.internal.visor.compute.VisorGatewayTask')
                 .addParam('p1', nid)
                 .addParam('p2', 
'org.apache.ignite.internal.visor.query.VisorQueryTask');
 
-            if (nonCollocatedJoins) {
+            if (enforceJoinOrder) {
+                cmd.addParam('p3', 
'org.apache.ignite.internal.visor.query.VisorQueryArgV3')
+                    .addParam('p4', cacheName)
+                    .addParam('p5', query)
+                    .addParam('p6', nonCollocatedJoins)
+                    .addParam('p7', enforceJoinOrder)
+                    .addParam('p8', local)
+                    .addParam('p9', pageSize);
+            }
+            else if (nonCollocatedJoins) {
                 cmd.addParam('p3', 
'org.apache.ignite.internal.visor.query.VisorQueryArgV2')
                     .addParam('p4', cacheName)
                     .addParam('p5', query)

http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/backend/app/browser.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/browser.js 
b/modules/web-console/backend/app/browser.js
index 56f2acc..00ae751 100644
--- a/modules/web-console/backend/app/browser.js
+++ b/modules/web-console/backend/app/browser.js
@@ -98,9 +98,9 @@ module.exports.factory = (_, socketio, agentMgr, configure) 
=> {
                 });
 
                 // Execute query on node and return first page to browser.
-                socket.on('node:query', (nid, cacheName, query, 
distributedJoins, local, pageSize, cb) => {
+                socket.on('node:query', (nid, cacheName, query, 
distributedJoins, enforceJoinOrder, local, pageSize, cb) => {
                     agentMgr.findAgent(accountId())
-                        .then((agent) => agent.fieldsQuery(demo, nid, 
cacheName, query, distributedJoins, local, pageSize))
+                        .then((agent) => agent.fieldsQuery(demo, nid, 
cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize))
                         .then((res) => cb(null, res))
                         .catch((err) => cb(_errorToJson(err)));
                 });
@@ -114,13 +114,13 @@ module.exports.factory = (_, socketio, agentMgr, 
configure) => {
                 });
 
                 // Execute query on node and return full result to browser.
-                socket.on('node:query:getAll', (nid, cacheName, query, 
distributedJoins, local, cb) => {
+                socket.on('node:query:getAll', (nid, cacheName, query, 
distributedJoins, enforceJoinOrder, local, cb) => {
                     // Set page size for query.
                     const pageSize = 1024;
 
                     agentMgr.findAgent(accountId())
                         .then((agent) => {
-                            const firstPage = agent.fieldsQuery(demo, nid, 
cacheName, query, distributedJoins, local, pageSize)
+                            const firstPage = agent.fieldsQuery(demo, nid, 
cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize)
                                 .then(({result}) => {
                                     if (result.key)
                                         return Promise.reject(result.key);

http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/app/modules/agent/agent.module.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/agent/agent.module.js 
b/modules/web-console/frontend/app/modules/agent/agent.module.js
index c0e92d5..724fc6c 100644
--- a/modules/web-console/frontend/app/modules/agent/agent.module.js
+++ b/modules/web-console/frontend/app/modules/agent/agent.module.js
@@ -265,12 +265,13 @@ class IgniteAgentMonitor {
      * @param {String} cacheName Cache name.
      * @param {String} [query] Query if null then scan query.
      * @param {Boolean} nonCollocatedJoins Flag whether to execute non 
collocated joins.
+     * @param {Boolean} enforceJoinOrder Flag whether enforce join order is 
enabled.
      * @param {Boolean} local Flag whether to execute query locally.
      * @param {int} pageSize
      * @returns {Promise}
      */
-    query(nid, cacheName, query, nonCollocatedJoins, local, pageSize) {
-        return this._rest('node:query', nid, maskNull(cacheName), 
maskNull(query), nonCollocatedJoins, local, pageSize)
+    query(nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, local, 
pageSize) {
+        return this._rest('node:query', nid, maskNull(cacheName), 
maskNull(query), nonCollocatedJoins, enforceJoinOrder, local, pageSize)
             .then(({result}) => {
                 if (_.isEmpty(result.key))
                     return result.value;
@@ -284,11 +285,12 @@ class IgniteAgentMonitor {
      * @param {String} cacheName Cache name.
      * @param {String} [query] Query if null then scan query.
      * @param {Boolean} nonCollocatedJoins Flag whether to execute non 
collocated joins.
+     * @param {Boolean} enforceJoinOrder Flag whether enforce join order is 
enabled.
      * @param {Boolean} local Flag whether to execute query locally.
      * @returns {Promise}
      */
-    queryGetAll(nid, cacheName, query, nonCollocatedJoins, local) {
-        return this._rest('node:query:getAll', nid, maskNull(cacheName), 
maskNull(query), nonCollocatedJoins, local);
+    queryGetAll(nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, 
local) {
+        return this._rest('node:query:getAll', nid, maskNull(cacheName), 
maskNull(query), nonCollocatedJoins, enforceJoinOrder, local);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/app/modules/sql/sql.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/sql/sql.controller.js 
b/modules/web-console/frontend/app/modules/sql/sql.controller.js
index c082d4e..7ded2d5 100644
--- a/modules/web-console/frontend/app/modules/sql/sql.controller.js
+++ b/modules/web-console/frontend/app/modules/sql/sql.controller.js
@@ -34,6 +34,8 @@ const SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE = 
'VISOR_SCAN_CACHE_WITH_FILTER_CASE
 
 const NON_COLLOCATED_JOINS_SINCE = '1.7.0';
 
+const ENFORCE_JOIN_VERS = [['1.7.9', '1.8.0'], ['1.8.4', '1.9.0'], ['1.9.1']];
+
 const _fullColName = (col) => {
     const res = [];
 
@@ -1336,7 +1338,8 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
             agentMonitor.awaitAgent()
                 .then(() => _closeOldQuery(paragraph))
                 .then(() => args.localNid || _chooseNode(args.cacheName, 
false))
-                .then((nid) => agentMonitor.query(nid, args.cacheName, 
args.query, args.nonCollocatedJoins, !!args.localNid, args.pageSize))
+                .then((nid) => agentMonitor.query(nid, args.cacheName, 
args.query, args.nonCollocatedJoins,
+                    args.enforceJoinOrder, !!args.localNid, args.pageSize))
                 .then(_processQueryResult.bind(this, paragraph, false))
                 .catch((err) => paragraph.errMsg = err.message);
         };
@@ -1369,8 +1372,18 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
             return false;
         };
 
+        $scope.enforceJoinOrderAvailable = (paragraph) => {
+            const cache = _.find($scope.caches, {name: paragraph.cacheName});
+
+            if (cache)
+                return !!_.find(cache.nodes, (node) => 
Version.includes(node.version, ...ENFORCE_JOIN_VERS));
+
+            return false;
+        };
+
         $scope.execute = (paragraph, local = false) => {
             const nonCollocatedJoins = !!paragraph.nonCollocatedJoins;
+            const enforceJoinOrder = !!paragraph.enforceJoinOrder;
 
             $scope.actionAvailable(paragraph, true) && 
_chooseNode(paragraph.cacheName, local)
                 .then((nid) => {
@@ -1390,6 +1403,7 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
                                 pageSize: paragraph.pageSize,
                                 maxPages: paragraph.maxPages,
                                 nonCollocatedJoins,
+                                enforceJoinOrder,
                                 localNid: local ? nid : null
                             };
 
@@ -1397,7 +1411,7 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
 
                             ActivitiesData.post({ action: '/queries/execute' 
});
 
-                            return agentMonitor.query(nid, args.cacheName, 
qry, nonCollocatedJoins, local, args.pageSize);
+                            return agentMonitor.query(nid, args.cacheName, 
qry, nonCollocatedJoins, enforceJoinOrder, local, args.pageSize);
                         })
                         .then((res) => {
                             _processQueryResult(paragraph, true, res);
@@ -1450,7 +1464,7 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
 
                     ActivitiesData.post({ action: '/queries/explain' });
 
-                    return agentMonitor.query(nid, args.cacheName, args.query, 
false, false, args.pageSize);
+                    return agentMonitor.query(nid, args.cacheName, args.query, 
false, !!paragraph.enforceJoinOrder, false, args.pageSize);
                 })
                 .then(_processQueryResult.bind(this, paragraph, true))
                 .catch((err) => {
@@ -1488,7 +1502,7 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
 
                             ActivitiesData.post({ action: '/queries/scan' });
 
-                            return agentMonitor.query(nid, args.cacheName, 
query, false, local, args.pageSize);
+                            return agentMonitor.query(nid, args.cacheName, 
query, false, false, local, args.pageSize);
                         })
                         .then((res) => _processQueryResult(paragraph, true, 
res))
                         .catch((err) => {
@@ -1609,7 +1623,8 @@ export default ['$rootScope', '$scope', '$http', '$q', 
'$timeout', '$interval',
             const args = paragraph.queryArgs;
 
             return Promise.resolve(args.localNid || 
_chooseNode(args.cacheName, false))
-                .then((nid) => agentMonitor.queryGetAll(nid, args.cacheName, 
args.query, !!args.nonCollocatedJoins, !!args.localNid))
+                .then((nid) => agentMonitor.queryGetAll(nid, args.cacheName, 
args.query, !!args.nonCollocatedJoins,
+                    !!args.enforceJoinOrder, !!args.localNid))
                 .then((res) => _export(paragraph.name + '-all.csv', 
paragraph.gridOptions.columnDefs, res.columns, res.rows))
                 .catch(Messages.showError)
                 .then(() => paragraph.ace && paragraph.ace.focus());

http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/public/stylesheets/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/public/stylesheets/style.scss 
b/modules/web-console/frontend/public/stylesheets/style.scss
index ab7e3dd..a07472e 100644
--- a/modules/web-console/frontend/public/stylesheets/style.scss
+++ b/modules/web-console/frontend/public/stylesheets/style.scss
@@ -809,7 +809,7 @@ button.form-control {
     }
 
     .btn-group {
-        vertical-align:top;
+        vertical-align: top;
         margin-left: 10px;
 
         i { line-height: 18px; }
@@ -1854,6 +1854,12 @@ th[st-sort] {
     display: inline-block;
 }
 
+.panel-top-align {
+    label {
+        vertical-align: top !important;
+    }
+}
+
 button.dropdown-toggle {
     margin-right: 5px;
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/views/sql/sql.tpl.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/views/sql/sql.tpl.pug 
b/modules/web-console/frontend/views/sql/sql.tpl.pug
index 931d632..bc134a6 100644
--- a/modules/web-console/frontend/views/sql/sql.tpl.pug
+++ b/modules/web-console/frontend/views/sql/sql.tpl.pug
@@ -91,20 +91,31 @@ mixin paragraph-rename
             input.form-control(id='paragraph-name-{{paragraph.id}}' 
ng-model='paragraph.editName' required ng-click='$event.stopPropagation();' 
ignite-on-enter='renameParagraph(paragraph, paragraph.editName)' 
ignite-on-escape='paragraph.edit = false')
 
 mixin query-settings
-    label.tipLabel(bs-tooltip data-placement='bottom' data-title='Configure 
periodical execution of last successfully executed query') Refresh rate:
-        button.btn.btn-default.fa.fa-clock-o.tipLabel(ng-class='{"btn-info": 
paragraph.rate && paragraph.rate.installed}' bs-popover data-template-url='{{ 
$ctrl.paragraphRateTemplateUrl }}' data-placement='left' data-auto-close='1' 
data-trigger='click') {{rateAsString(paragraph)}}
-
-    label.tipLabel(bs-tooltip data-placement='bottom' data-title='Max number 
of rows to show in query result as one page') Page size:
-        
button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.pageSize' 
bs-select bs-options='item for item in pageSizes')
-
-    label.tipLabel(bs-tooltip data-placement='bottom' data-title='Limit query 
max results to specified number of pages') Max pages:
-        
button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.maxPages' 
bs-select bs-options='item.value as item.label for item in maxPages')
-
-    label.tipLabel(ng-if='nonCollocatedJoinsAvailable(paragraph)' bs-tooltip 
data-placement='bottom' data-title='Non-collocated joins is a special mode that 
allow to join data across cluster without collocation.<br/>\
-        Nested joins are not supported for now.<br/>\
-        <b>NOTE</b>: In some cases it may consume more heap memory or may take 
a long time than collocated joins.' data-trigger='hover')
-        input(type='checkbox' ng-model='paragraph.nonCollocatedJoins')
-        span Allow non-collocated joins
+    .panel-top-align
+        label.tipLabel(bs-tooltip data-placement='bottom' 
data-title='Configure periodical execution of last successfully executed 
query') Refresh rate:
+            
button.btn.btn-default.fa.fa-clock-o.tipLabel(ng-class='{"btn-info": 
paragraph.rate && paragraph.rate.installed}' bs-popover data-template-url='{{ 
$ctrl.paragraphRateTemplateUrl }}' data-placement='left' data-auto-close='1' 
data-trigger='click') {{rateAsString(paragraph)}}
+
+        label.tipLabel(bs-tooltip data-placement='bottom' data-title='Max 
number of rows to show in query result as one page') Page size:
+            
button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.pageSize' 
bs-select bs-options='item for item in pageSizes')
+
+        label.tipLabel(bs-tooltip data-placement='bottom' data-title='Limit 
query max results to specified number of pages') Max pages:
+            
button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.maxPages' 
bs-select bs-options='item.value as item.label for item in maxPages')
+
+        .panel-tip-container
+            .row(ng-if='nonCollocatedJoinsAvailable(paragraph)')
+                label.tipLabel(bs-tooltip data-placement='bottom' 
data-title='Non-collocated joins is a special mode that allow to join data 
across cluster without collocation.<br/>\
+                    Nested joins are not supported for now.<br/>\
+                    <b>NOTE</b>: In some cases it may consume more heap memory 
or may take a long time than collocated joins.' data-trigger='hover')
+                    input(type='checkbox' 
ng-model='paragraph.nonCollocatedJoins')
+                    span Allow non-collocated joins
+            .row(ng-if='enforceJoinOrderAvailable(paragraph)')
+                label.tipLabel(bs-tooltip data-placement='bottom' 
data-title='Enforce join order of tables in the query.<br/>\
+                    If <b>set</b> then query optimizer will not reorder tables 
in join.<br/>\
+                    <b>NOTE:</b> It is not recommended to enable this property 
until you are sure that\
+                    your indexes and the query itself are correct and tuned as 
much as possible but\
+                    query optimizer still produces wrong join order.' 
data-trigger='hover')
+                    input(type='checkbox' 
ng-model='paragraph.enforceJoinOrder')
+                    span Enforce join order
 
 mixin query-actions
     button.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, true)' 
ng-click='execute(paragraph)') Execute

Reply via email to