mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:arangodb/arangodb into devel
* 'devel' of github.com:arangodb/arangodb: grunt build [ci skip] aql tabular output fixed issue #1949 fixed issue #1950
This commit is contained in:
commit
95b5c3b50c
|
@ -32,6 +32,10 @@ devel
|
|||
v3.0.4 (XXXX-XX-XX)
|
||||
-------------------
|
||||
|
||||
* fixed issue #1950
|
||||
|
||||
* fixed issue #1949
|
||||
|
||||
* fixed segfault in V8, by backporting https://bugs.chromium.org/p/v8/issues/detail?id=5033
|
||||
|
||||
* Foxx OAuth2 module now correctly passes the `access_token` to the OAuth2 server
|
||||
|
|
|
@ -1239,12 +1239,12 @@ class arangodb::aql::RedundantCalculationsReplacer final
|
|||
public:
|
||||
explicit RedundantCalculationsReplacer(
|
||||
std::unordered_map<VariableId, Variable const*> const& replacements)
|
||||
: _replacements(replacements) {}
|
||||
: _replacements(replacements) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void replaceInVariable(ExecutionNode* en) {
|
||||
auto node = static_cast<T*>(en);
|
||||
|
||||
node->_inVariable = Variable::replace(node->_inVariable, _replacements);
|
||||
}
|
||||
|
||||
|
@ -1252,7 +1252,7 @@ class arangodb::aql::RedundantCalculationsReplacer final
|
|||
auto node = static_cast<CalculationNode*>(en);
|
||||
std::unordered_set<Variable const*> variables;
|
||||
node->expression()->variables(variables);
|
||||
|
||||
|
||||
// check if the calculation uses any of the variables that we want to
|
||||
// replace
|
||||
for (auto const& it : variables) {
|
||||
|
@ -3784,6 +3784,14 @@ void arangodb::aql::inlineSubqueriesRule(Optimizer* opt,
|
|||
auto queryVariables = plan->getAst()->variables();
|
||||
std::vector<ExecutionNode*> subNodes(subqueryNode->getSubquery()->getDependencyChain(true));
|
||||
|
||||
// check if the subquery result variable is used after the FOR loop as well
|
||||
std::unordered_set<Variable const*> varsUsedLater(listNode->getVarsUsedLater());
|
||||
if (varsUsedLater.find(listNode->inVariable()) != varsUsedLater.end()) {
|
||||
// exit the loop
|
||||
current = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
TRI_ASSERT(! subNodes.empty());
|
||||
auto returnNode = static_cast<ReturnNode*>(subNodes[0]);
|
||||
TRI_ASSERT(returnNode->getType() == EN::RETURN);
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -2270,7 +2270,14 @@ if (list.length > 0) {
|
|||
<div class="pull-right">
|
||||
<span class="action"><i class="fa fa-close" element="outputEditor<%= counter %>" style="display: none"></i></span>
|
||||
</div>
|
||||
<div class="pull-right"> <% if (type === 'Query') { %> <span class="switchAce" counter="<%=counter%>" style="display: none">Result</span> <% } else { %> <span class="switchAce" counter="<%=counter%>">AQL</span> <% } %> </div>
|
||||
<div class="pull-right">
|
||||
<div class="switchAce" counter="<%=counter%>">
|
||||
<span id="json-switch" val="JSON" counter="<%=counter%>">JSON</span>
|
||||
<span id="table-switch" val="Table" counter="<%=counter%>" style="display: none">Table</span>
|
||||
<span id="graph-switch" val="Graph" counter="<%=counter%>" style="display: none">Graph</span>
|
||||
<span id="aql-switch" val="AQL" counter="<%=counter%>">AQL</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="outputEditor<%= counter %>" style="opacity: 0.5"></div>
|
||||
<div id="sentWrapper<%= counter %>" class="sentWrapper" style="display: none">
|
||||
|
@ -2698,4 +2705,4 @@ var cutByResolution = function (str) {
|
|||
</div>
|
||||
|
||||
<div id="workMonitorContent" class="innerContent">
|
||||
</div></script></head><body><nav class="navbar" style="display: none"><div class="primary"><div class="navlogo"><a class="logo big" href="#"><img class="arangodbLogo" src="img/arangodb_logo_big.png"></a><a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a><a class="version"><span>VERSION: </span><span id="currentVersion"></span></a></div><div class="statmenu" id="statisticBar"></div><div class="navmenu" id="navigationBar"></div></div></nav><div id="modalPlaceholder"></div><div class="bodyWrapper" style="display: none"><div class="centralRow"><div id="navbar2" class="navbarWrapper secondary"><div class="subnavmenu" id="subNavigationBar"></div></div><div class="resizecontainer contentWrapper"><div id="loadingScreen" class="loadingScreen" style="display: none"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw margin-bottom"></i> <span class="sr-only">Loading...</span></div><div id="content" class="centralContent"></div><footer class="footer"><div id="footerBar"></div></footer></div></div></div><div id="progressPlaceholder" style="display:none"></div><div id="spotlightPlaceholder" style="display:none"></div><div id="graphSettingsContent" style="display: none"></div><div id="offlinePlaceholder" style="display:none"><div class="offline-div"><div class="pure-u"><div class="pure-u-1-4"></div><div class="pure-u-1-2 offline-window"><div class="offline-header"><h3>You have been disconnected from the server</h3></div><div class="offline-body"><p>The connection to the server has been lost. The server may be under heavy load.</p><p>Trying to reconnect in <span id="offlineSeconds">10</span> seconds.</p><p class="animation_state"><span><button class="button-success">Reconnect now</button></span></p></div></div><div class="pure-u-1-4"></div></div></div></div><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="libs.js?version=1468931748660"></script><script src="app.js?version=1468931748660"></script></body></html>
|
||||
</div></script></head><body><nav class="navbar" style="display: none"><div class="primary"><div class="navlogo"><a class="logo big" href="#"><img class="arangodbLogo" src="img/arangodb_logo_big.png"></a><a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a><a class="version"><span>VERSION: </span><span id="currentVersion"></span></a></div><div class="statmenu" id="statisticBar"></div><div class="navmenu" id="navigationBar"></div></div></nav><div id="modalPlaceholder"></div><div class="bodyWrapper" style="display: none"><div class="centralRow"><div id="navbar2" class="navbarWrapper secondary"><div class="subnavmenu" id="subNavigationBar"></div></div><div class="resizecontainer contentWrapper"><div id="loadingScreen" class="loadingScreen" style="display: none"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw margin-bottom"></i> <span class="sr-only">Loading...</span></div><div id="content" class="centralContent"></div><footer class="footer"><div id="footerBar"></div></footer></div></div></div><div id="progressPlaceholder" style="display:none"></div><div id="spotlightPlaceholder" style="display:none"></div><div id="graphSettingsContent" style="display: none"></div><div id="offlinePlaceholder" style="display:none"><div class="offline-div"><div class="pure-u"><div class="pure-u-1-4"></div><div class="pure-u-1-2 offline-window"><div class="offline-header"><h3>You have been disconnected from the server</h3></div><div class="offline-body"><p>The connection to the server has been lost. The server may be under heavy load.</p><p>Trying to reconnect in <span id="offlineSeconds">10</span> seconds.</p><p class="animation_state"><span><button class="button-success">Reconnect now</button></span></p></div></div><div class="pure-u-1-4"></div></div></div></div><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="libs.js?version=1469003996721"></script><script src="app.js?version=1469003996721"></script></body></html>
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
@ -194,7 +194,7 @@
|
|||
|
||||
// fetch just the first 25 attributes of the document
|
||||
// this number is arbitrary, but may reduce HTTP traffic a bit
|
||||
query = 'FOR x IN @@collection LET att = SLICE(ATTRIBUTES(x), 0, 25)';
|
||||
query = 'FOR x IN @@collection LET att = APPEND(SLICE(ATTRIBUTES(x), 0, 25), "_key", true)';
|
||||
query += this.setFiltersForQuery(bindVars);
|
||||
// Sort result, only useful for a small number of docs
|
||||
if (this.getTotal() < this.MAX_SORT) {
|
||||
|
|
|
@ -1475,13 +1475,19 @@
|
|||
var result = self.analyseQuery(data.result);
|
||||
console.log('Using ' + result.defaultType + ' as data format.');
|
||||
if (result.defaultType === 'table') {
|
||||
$('#outputEditorWrapper' + counter).append('<div id="outputTable' + counter + '"></div>');
|
||||
$('#outputEditorWrapper' + counter + ' .arangoToolbarTop').after('<div id="outputTable' + counter + '"></div>');
|
||||
$('#outputTable' + counter).show();
|
||||
self.renderOutputTable(result, counter);
|
||||
|
||||
// apply max height for table output dynamically
|
||||
var maxHeight = $('.centralRow').height() - 250;
|
||||
$('.outputEditorWrapper .tableWrapper').css('max-height', maxHeight);
|
||||
|
||||
$('#outputEditor' + counter).hide();
|
||||
} else if (result.defaultType === 'graph') {
|
||||
$('#outputEditorWrapper' + counter).append('<div id="outputGraph' + counter + '"></div>');
|
||||
$('#outputEditorWrapper' + counter + ' .arangoToolbarTop').after('<div id="outputGraph' + counter + '"></div>');
|
||||
$('#outputGraph' + counter).show();
|
||||
self.renderOutputGraph(result, data);
|
||||
|
||||
$('#outputEditor' + counter).hide();
|
||||
}
|
||||
|
@ -1618,82 +1624,92 @@
|
|||
|
||||
// check if result could be displayed as graph
|
||||
// case a) result has keys named vertices and edges
|
||||
if (result[0].vertices && result[0].edges) {
|
||||
var hitsa = 0;
|
||||
var totala = 0;
|
||||
if (result[0]) {
|
||||
if (result[0].vertices && result[0].edges) {
|
||||
var hitsa = 0;
|
||||
var totala = 0;
|
||||
|
||||
_.each(result, function (obj) {
|
||||
if (obj.edges) {
|
||||
totala += obj.edges.length;
|
||||
_.each(result, function (obj) {
|
||||
if (obj.edges) {
|
||||
totala += obj.edges.length;
|
||||
|
||||
_.each(obj.edges, function (edge) {
|
||||
if (edge._from && edge._to) {
|
||||
hitsa++;
|
||||
}
|
||||
});
|
||||
_.each(obj.edges, function (edge) {
|
||||
if (edge._from && edge._to) {
|
||||
hitsa++;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var percentagea = hitsa / totala * 100;
|
||||
|
||||
if (percentagea >= 95) {
|
||||
found = true;
|
||||
toReturn.defaultType = 'graph';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// case b) 95% have _from and _to attribute
|
||||
var hitsb = 0;
|
||||
var totalb = result.length;
|
||||
|
||||
var percentagea = hitsa / totala * 100;
|
||||
_.each(result, function (obj) {
|
||||
if (obj._from && obj._to) {
|
||||
hitsb++;
|
||||
}
|
||||
});
|
||||
|
||||
if (percentagea >= 95) {
|
||||
found = true;
|
||||
toReturn.defaultType = 'graph';
|
||||
}
|
||||
} else {
|
||||
// case b) 95% have _from and _to attribute
|
||||
var hitsb = 0;
|
||||
var totalb = result.length;
|
||||
var percentageb = hitsb / totalb * 100;
|
||||
|
||||
_.each(result, function (obj) {
|
||||
if (obj._from && obj._to) {
|
||||
hitsb++;
|
||||
if (percentageb >= 95) {
|
||||
found = true;
|
||||
toReturn.defaultType = 'graph';
|
||||
// then display as graph
|
||||
}
|
||||
});
|
||||
|
||||
var percentageb = hitsb / totalb * 100;
|
||||
|
||||
if (percentageb >= 95) {
|
||||
found = true;
|
||||
toReturn.defaultType = 'graph';
|
||||
// then display as graph
|
||||
}
|
||||
}
|
||||
|
||||
// check if result could be displayed as table
|
||||
if (!found) {
|
||||
var maxAttributeCount = 0;
|
||||
var check = true;
|
||||
var length;
|
||||
var attributes = {};
|
||||
|
||||
_.each(result, function (obj) {
|
||||
length = _.keys(obj).length;
|
||||
if (result.length <= 1) {
|
||||
check = false;
|
||||
}
|
||||
|
||||
if (length > maxAttributeCount) {
|
||||
maxAttributeCount = length;
|
||||
}
|
||||
if (check) {
|
||||
_.each(result, function (obj) {
|
||||
length = _.keys(obj).length;
|
||||
|
||||
_.each(obj, function (value, key) {
|
||||
if (attributes[key]) {
|
||||
attributes[key] = attributes[key] + 1;
|
||||
} else {
|
||||
attributes[key] = 1;
|
||||
if (length > maxAttributeCount) {
|
||||
maxAttributeCount = length;
|
||||
}
|
||||
|
||||
_.each(obj, function (value, key) {
|
||||
if (attributes[key]) {
|
||||
attributes[key] = attributes[key] + 1;
|
||||
} else {
|
||||
attributes[key] = 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var rate;
|
||||
|
||||
console.log(attributes);
|
||||
_.each(attributes, function (val, key) {
|
||||
rate = (val / result.length) * 100;
|
||||
|
||||
console.log(rate);
|
||||
if (check !== false) {
|
||||
if (rate <= 95) {
|
||||
check = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var rate;
|
||||
var check = true;
|
||||
|
||||
_.each(attributes, function (val, key) {
|
||||
rate = (val / result.length) * 100;
|
||||
|
||||
if (check !== false) {
|
||||
if (rate <= 95) {
|
||||
check = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (check) {
|
||||
found = true;
|
||||
|
@ -1784,6 +1800,42 @@
|
|||
});
|
||||
},
|
||||
|
||||
renderOutputTable: function (data, counter) {
|
||||
var tableDescription = {
|
||||
id: 'outputTableData' + counter,
|
||||
titles: [],
|
||||
rows: []
|
||||
};
|
||||
|
||||
var first = true;
|
||||
var part = [];
|
||||
// self.tableDescription.rows.push(;
|
||||
_.each(data.original, function (obj) {
|
||||
if (first === true) {
|
||||
tableDescription.titles = Object.keys(obj);
|
||||
first = false;
|
||||
}
|
||||
_.each(obj, function (val) {
|
||||
if (typeof val === 'object') {
|
||||
val = JSON.stringify(val);
|
||||
}
|
||||
part.push(val);
|
||||
});
|
||||
tableDescription.rows.push(part);
|
||||
part = [];
|
||||
});
|
||||
|
||||
console.log(counter);
|
||||
$('#outputTable' + counter).append(this.table.render({content: tableDescription}));
|
||||
|
||||
console.log(tableDescription.titles);
|
||||
console.log(tableDescription.rows);
|
||||
},
|
||||
|
||||
renderOutputGraph: function () {
|
||||
|
||||
},
|
||||
|
||||
getAQL: function (originCallback) {
|
||||
var self = this;
|
||||
|
||||
|
|
|
@ -328,7 +328,6 @@
|
|||
.ui-resizable-e {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.queryContent {
|
||||
|
@ -356,6 +355,16 @@
|
|||
padding-top: 20px;
|
||||
width: 100%;
|
||||
|
||||
.tableWrapper {
|
||||
max-width: 100%;
|
||||
overflow-x: scroll;
|
||||
|
||||
.arango-table {
|
||||
border-left: 1px solid $c-content-border;
|
||||
border-right: 1px solid $c-content-border;
|
||||
}
|
||||
}
|
||||
|
||||
.switchAce {
|
||||
background-color: rgba(0, 0, 0, .6);
|
||||
border-radius: 3px;
|
||||
|
|
|
@ -469,6 +469,12 @@ function removeClusterNodes (nodeTypes) {
|
|||
});
|
||||
}
|
||||
|
||||
function removeClusterNodesFromPlan (nodes) {
|
||||
return nodes.filter(function (node) {
|
||||
return ([ 'ScatterNode', 'GatherNode', 'DistributeNode', 'RemoteNode' ].indexOf(node.type) === -1);
|
||||
});
|
||||
}
|
||||
|
||||
exports.isEqual = isEqual;
|
||||
exports.getParseResults = getParseResults;
|
||||
exports.assertParseError = assertParseError;
|
||||
|
@ -487,3 +493,4 @@ exports.findReferencedNodes = findReferencedNodes;
|
|||
exports.getQueryMultiplePlansAndExecutions = getQueryMultiplePlansAndExecutions;
|
||||
exports.removeAlwaysOnClusterRules = removeAlwaysOnClusterRules;
|
||||
exports.removeClusterNodes = removeClusterNodes;
|
||||
exports.removeClusterNodesFromPlan = removeClusterNodesFromPlan;
|
||||
|
|
|
@ -31,14 +31,14 @@
|
|||
var jsunity = require("jsunity");
|
||||
var helper = require("@arangodb/aql-helper");
|
||||
var isEqual = helper.isEqual;
|
||||
var db = require("@arangodb").db;
|
||||
var ruleName = "inline-subqueries";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function optimizerRuleTestSuite () {
|
||||
var ruleName = "inline-subqueries";
|
||||
|
||||
// various choices to control the optimizer:
|
||||
var paramNone = { optimizer: { rules: [ "-all" ] } };
|
||||
var paramEnabled = { optimizer: { rules: [ "-all", "+" + ruleName ] }, inspectSimplePlans: true };
|
||||
|
@ -161,8 +161,73 @@ function optimizerRuleTestSuite () {
|
|||
result = AQL_EXECUTE(query[0]).json;
|
||||
assertEqual(query[1], result, query);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function optimizerRuleCollectionTestSuite () {
|
||||
var c = null;
|
||||
var cn = "UnitTestsOptimizer";
|
||||
|
||||
return {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
setUp : function () {
|
||||
db._drop(cn);
|
||||
c = db._create(cn);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tear down
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
tearDown : function () {
|
||||
db._drop(cn);
|
||||
c = null;
|
||||
},
|
||||
|
||||
testSpecificPlan1 : function () {
|
||||
var query = "LET x = (FOR doc IN @@cn RETURN doc) FOR doc2 IN x RETURN doc2";
|
||||
|
||||
var result = AQL_EXPLAIN(query, { "@cn" : cn });
|
||||
assertNotEqual(-1, result.plan.rules.indexOf(ruleName), query);
|
||||
var nodes = helper.removeClusterNodesFromPlan(result.plan.nodes);
|
||||
assertEqual(3, nodes.length);
|
||||
assertEqual("ReturnNode", nodes[nodes.length - 1].type);
|
||||
assertEqual("doc2", nodes[nodes.length - 1].inVariable.name);
|
||||
assertEqual("EnumerateCollectionNode", nodes[nodes.length - 2].type);
|
||||
assertEqual(cn, nodes[nodes.length - 2].collection);
|
||||
},
|
||||
|
||||
testSpecificPlan2 : function () {
|
||||
var query = "LET x = (FOR doc IN @@cn FILTER doc.foo == 'bar' RETURN doc) FOR doc2 IN x RETURN doc2";
|
||||
|
||||
var result = AQL_EXPLAIN(query, { "@cn" : cn });
|
||||
assertNotEqual(-1, result.plan.rules.indexOf(ruleName), query);
|
||||
var nodes = helper.removeClusterNodesFromPlan(result.plan.nodes);
|
||||
assertEqual(5, nodes.length);
|
||||
assertEqual("ReturnNode", nodes[nodes.length - 1].type);
|
||||
assertEqual("doc2", nodes[nodes.length - 1].inVariable.name);
|
||||
assertEqual("FilterNode", nodes[nodes.length - 2].type);
|
||||
assertEqual("CalculationNode", nodes[nodes.length - 3].type);
|
||||
assertEqual("EnumerateCollectionNode", nodes[nodes.length - 4].type);
|
||||
assertEqual(cn, nodes[nodes.length - 4].collection);
|
||||
},
|
||||
|
||||
testSpecificPlan3 : function () {
|
||||
var query = "LET x = (FOR doc IN @@cn RETURN doc) FOR doc2 IN x RETURN x";
|
||||
var result = AQL_EXPLAIN(query, { "@cn" : cn });
|
||||
assertEqual(-1, result.plan.rules.indexOf(ruleName), query); // no optimization
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -171,5 +236,6 @@ function optimizerRuleTestSuite () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
jsunity.run(optimizerRuleTestSuite);
|
||||
jsunity.run(optimizerRuleCollectionTestSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
|
Loading…
Reference in New Issue