10000 backport of #10231 · arangodb/arangodb@bc4154d · GitHub
[go: up one dir, main page]

Skip to content

Commit bc4154d

Browse files
committed
backport of #10231
1 parent ae508c7 commit bc4154d

File tree

6 files changed

+50
-2
lines changed

6 files changed

+50
-2
lines changed

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
v3.4.9 (XXX-XX-XX)
22
-------------------
33

4+
* Disallow the usage of subqueries inside AQL traversal PRUNE conditions.
5+
Using subqueries inside PRUNE conditions causes undefined behavior,
6+
so such queries will now be aborted early on with a parse error
7+
instead of running into undefined behavior.
8+
49
* Fixed search not working in document view while in code mode.
510

611
* Fixed issue #10090: fix repeatable seek to the same document in

arangod/Aql/Ast.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,23 @@ AstNode* Ast::createNodeReference(Variable const* variable) {
743743
return node;
744744
}
745745

746+
/// @brief create an AST subquery reference node
747+
AstNode* Ast::createNodeSubqueryReference(std::string const& variableName) {
748+
AstNode* node = createNode(NODE_TYPE_REFERENCE);
749+
node->setFlag(AstNodeFlagType::FLAG_SUBQUERY_REFERENCE);
750+
751+
auto variable = _scopes.getVariable(variableName);
752+
753+
if (variable == nullptr) {
754+
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
755+
"variable not found in reference AstNode");
756+
}
757+
758+
node->setData(variable);
759+
760+
return node;
761+
}
762+
746763
/// @brief create an AST variable access
747764
AstNode* Ast::createNodeAccess(Variable const* variable,
748765
std::vector<basics::AttributeName> const& field) {

arangod/Aql/Ast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ class Ast {
246246
/// @brief create an AST reference node
247247
AstNode* createNodeReference(Variable const* variable);
248248

249+
/// @brief create an AST subquery reference node
250+
AstNode* createNodeSubqueryReference(std::string const& variableName);
251+
249252
/// @brief create an AST parameter node for a value literal
250253
AstNode* createNodeParameter(char const* name, size_t length);
251254

arangod/Aql/AstNode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ enum AstNodeFlagType : AstNodeFlagsType {
7171
FLAG_KEEP_VARIABLENAME = 0x0010000, // node is a reference to a variable name, not the variable value (used in KEEP nodes)
7272
FLAG_BIND_PARAMETER = 0x0020000, // node was created from a bind parameter
7373
FLAG_FINALIZED = 0x0040000, // node has been finalized and should not be modified; only set and checked in maintainer mode
74+
FLAG_SUBQUERY_REFERENCE = 0x0080000, // node references a subquery
7475
};
7576

7677
/// @brief enumeration of AST node value types

arangod/Aql/grammar.y

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,6 @@ prune_and_options:
566566
node->addMember($2);
567567
// Options
568568
node->addMember($4);
569-
570569
}
571570
;
572571

@@ -687,6 +686,15 @@ for_statement:
687686
} prune_and_options {
688687
auto graphInfoNode = static_cast<AstNode*>(parser->popStack());
689688
auto variablesNode = static_cast<AstNode*>(parser->popStack());
689+
690+
auto prune = graphInfoNode->getMember(3);
691+
if (prune != nullptr) {
692+
Ast::traverseReadOnly(prune, [&](AstNode const* node) {
693+
if (node->type == NODE_TYPE_REFERENCE && node->hasFlag(AstNodeFlagType::FLAG_SUBQUERY_REFERENCE)) {
694+
parser->registerParseError(TRI_ERROR_QUERY_PARSE, "prune condition must not use a subquery", yylloc.first_line, yylloc.first_column);
695+
}
696+
});
697+
}
690698
auto node = parser->ast()->createNodeTraversal(variablesNode, graphInfoNode);
691699
parser->ast()->addOperation(node);
692700
}
@@ -1416,7 +1424,7 @@ expression_or_query:
14161424
auto subQuery = parser->ast()->createNodeLet(variableName.c_str(), variableName.size(), node, false);
14171425
parser->ast()->addOperation(subQuery);
14181426

1419-
$$ = parser->ast()->createNodeReference(variableName);
1427+
$$ = parser->ast()->createNodeSubqueryReference(variableName);
14201428
}
14211429
;
14221430

tests/js/server/aql/aql-graph-traverser.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,20 @@ function complexFilteringSuite() {
20212021

20222022
tearDownAll: cleanup,
20232023

2024+
testPruneWithSubquery: function () {
2025+
let query = `FOR v,e,p IN 1..100 OUTBOUND @start @ecol PRUNE 2 <= LENGTH(FOR w IN p.vertices FILTER w._id == v._id RETURN 1) RETURN p`;
2026+
try {
2027+
let bindVars = {
2028+
'@eCol': en,
2029+
'start': vertex.Tri1
2030+
};
2031+
db._query(query, bindVars);
2032+
fail();
2033+
} catch (err) {
2034+
assertEqual(err.errorNum, errors.ERROR_QUERY_PARSE.code);
2035+
}
2036+
},
2037+
20242038
testVertexEarlyPruneHighDepth: function () {
20252039
var query = `WITH ${vn}
20262040
FOR v, e, p IN 100 OUTBOUND @start @@eCol

0 commit comments

Comments
 (0)
0