diff --git a/CHANGELOG b/CHANGELOG index cd49efcf9c07..41f5bedd27b8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ devel ----- +* Fixed BTS-562: reduce-extraction-to-projection optimization returns null for + one attribute if nested attributes are named the same. + * Add `--datatype` startup option to arangoimport, in order to hard-code the datatype (null/boolean/number/string) for certain attributes in the CSV/TSV import. For example, given the following input file: diff --git a/arangod/Aql/AttributeNamePath.cpp b/arangod/Aql/AttributeNamePath.cpp index c878304cd0ef..0a733bd48e70 100644 --- a/arangod/Aql/AttributeNamePath.cpp +++ b/arangod/Aql/AttributeNamePath.cpp @@ -133,9 +133,10 @@ AttributeNamePath& AttributeNamePath::shortenTo(size_t length) { size_t numEqual = 0; size_t commonLength = std::min(lhs.size(), rhs.size()); for (size_t i = 0; i < commonLength; ++i) { - if (lhs[i] == rhs[i]) { - ++numEqual; + if (lhs[i] != rhs[i]) { + break; } + ++numEqual; } return numEqual; } diff --git a/tests/js/server/aql/aql-optimizer-rule-reduce-extraction-to-projection.js b/tests/js/server/aql/aql-optimizer-rule-reduce-extraction-to-projection.js index 841b94447d1d..12236626f76f 100644 --- a/tests/js/server/aql/aql-optimizer-rule-reduce-extraction-to-projection.js +++ b/tests/js/server/aql/aql-optimizer-rule-reduce-extraction-to-projection.js @@ -274,8 +274,49 @@ function optimizerRuleTestSuite () { assertEqual(2, found); }); - } - + }, + + testBts562 : function () { + c.truncate(); + c.insert({ foo: { attr: 1 }, bar: { attr: 2 } }); + + let result = AQL_EXECUTE(`FOR doc IN @@cn RETURN [ doc.foo.attr, doc.bar.attr ]`, { "@cn" : cn }).json; + assertEqual(1, result.length); + assertEqual([ 1, 2 ], result[0]); + + c.truncate(); + c.insert({ foo: { attr: 1 }, bar: { attr: 2 }, baz: { attr: 3 } }); + + result = AQL_EXECUTE(`FOR doc IN @@cn RETURN [ doc.foo.attr, doc.bar.attr, doc.baz.attr ]`, { "@cn" : cn }).json; + assertEqual(1, result.length); + assertEqual([ 1, 2, 3 ], result[0]); + + c.truncate(); + c.insert({ result: {} }); + c.insert({ result: { status: "ok" } }); + + result = AQL_EXECUTE(`FOR d IN @@cn COLLECT resultStatus = d.result.status, requestStatus = d.request.status WITH COUNT INTO count SORT resultStatus RETURN { resultStatus, requestStatus, count }`, { "@cn": cn }).json; + + assertEqual(2, result.length); + assertEqual({ resultStatus: null, requestStatus: null, count: 1 }, result[0]); + assertEqual({ resultStatus: "ok", requestStatus: null, count: 1 }, result[1]); + + result = AQL_EXECUTE(`FOR d IN @@cn COLLECT resultStatus = d.result.status, requestOther = d.request.other WITH COUNT INTO count SORT resultStatus RETURN { resultStatus, requestOther, count }`, { "@cn" : cn }).json; + assertEqual(2, result.length); + assertEqual({ resultStatus: null, requestOther: null, count: 1 }, result[0]); + assertEqual({ resultStatus: "ok", requestOther: null, count: 1 }, result[1]); + + c.truncate(); + c.insert({ result: { status: "ok" }, request: { status: "ok" } }); + c.insert({ result: { status: "ok" }, request: { status: "blarg" } }); + + result = AQL_EXECUTE(`FOR d IN @@cn COLLECT resultStatus = d.result.status, requestStatus = d.request.status WITH COUNT INTO count SORT requestStatus RETURN { resultStatus, requestStatus, count }`, { "@cn" : cn }).json; + + assertEqual(2, result.length); + assertEqual({ resultStatus: "ok", requestStatus: "blarg", count: 1 }, result[0]); + assertEqual({ resultStatus: "ok", requestStatus: "ok", count: 1 }, result[1]); + }, + }; }