From 840885c641f15afd6ed277318bfdf205880e04df Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Thu, 24 Feb 2022 14:09:22 +0800 Subject: [PATCH 1/7] Add match path pattern expression. --- src/codec/test/CMakeLists.txt | 1 + src/common/datatypes/test/CMakeLists.txt | 2 + src/common/expression/CMakeLists.txt | 1 + src/common/expression/ExprVisitor.h | 3 + src/common/expression/Expression.cpp | 7 + src/common/expression/Expression.h | 2 + .../expression/MatchPathPatternExpression.cpp | 50 +++ .../expression/MatchPathPatternExpression.h | 70 ++++ src/common/expression/test/CMakeLists.txt | 4 + src/common/id/test/CMakeLists.txt | 2 + src/common/utils/test/CMakeLists.txt | 3 + src/daemons/CMakeLists.txt | 3 + src/graph/context/test/CMakeLists.txt | 2 + src/graph/executor/test/CMakeLists.txt | 2 + src/graph/optimizer/test/CMakeLists.txt | 2 + src/graph/planner/test/CMakeLists.txt | 2 + src/graph/util/test/CMakeLists.txt | 2 + src/graph/validator/test/CMakeLists.txt | 1 + src/graph/visitor/DeduceTypeVisitor.cpp | 5 + src/graph/visitor/DeduceTypeVisitor.h | 2 + src/graph/visitor/ExprVisitorImpl.cpp | 10 + src/graph/visitor/ExprVisitorImpl.h | 2 + src/graph/visitor/FoldConstantExprVisitor.cpp | 4 + src/graph/visitor/FoldConstantExprVisitor.h | 2 + src/graph/visitor/RewriteSymExprVisitor.cpp | 13 + src/graph/visitor/RewriteSymExprVisitor.h | 2 + src/graph/visitor/VidExtractVisitor.cpp | 5 + src/graph/visitor/VidExtractVisitor.h | 2 + src/graph/visitor/test/CMakeLists.txt | 1 + src/kvstore/test/CMakeLists.txt | 1 + src/meta/CMakeLists.txt | 1 + src/parser/CMakeLists.txt | 5 + src/parser/MatchPath.cpp | 108 ++++++ src/parser/MatchPath.h | 319 ++++++++++++++++++ src/parser/MatchSentence.cpp | 98 ------ src/parser/MatchSentence.h | 246 +------------- src/parser/parser.yy | 10 + src/parser/test/CMakeLists.txt | 1 + src/parser/test/ParserTest.cpp | 18 + src/storage/ExprVisitorBase.cpp | 4 + src/storage/ExprVisitorBase.h | 2 + src/storage/query/QueryBaseProcessor-inl.h | 3 +- src/storage/test/CMakeLists.txt | 1 + src/tools/db-dump/CMakeLists.txt | 1 + src/tools/db-upgrade/CMakeLists.txt | 1 + src/tools/meta-dump/CMakeLists.txt | 1 + src/tools/simple-kv-verify/CMakeLists.txt | 1 + src/tools/storage-perf/CMakeLists.txt | 1 + 48 files changed, 685 insertions(+), 344 deletions(-) create mode 100644 src/common/expression/MatchPathPatternExpression.cpp create mode 100644 src/common/expression/MatchPathPatternExpression.h create mode 100644 src/parser/MatchPath.cpp create mode 100644 src/parser/MatchPath.h diff --git a/src/codec/test/CMakeLists.txt b/src/codec/test/CMakeLists.txt index 1bf4e06fe07..a9faf33e216 100644 --- a/src/codec/test/CMakeLists.txt +++ b/src/codec/test/CMakeLists.txt @@ -30,6 +30,7 @@ set(CODEC_TEST_LIBS $ $ $ + $ $ $ $ diff --git a/src/common/datatypes/test/CMakeLists.txt b/src/common/datatypes/test/CMakeLists.txt index beff0176017..0fdc5fde32c 100644 --- a/src/common/datatypes/test/CMakeLists.txt +++ b/src/common/datatypes/test/CMakeLists.txt @@ -38,6 +38,7 @@ nebula_add_test( OBJECTS $ $ + $ $ $ $ @@ -107,6 +108,7 @@ nebula_add_test( OBJECTS $ $ + $ $ $ $ diff --git a/src/common/expression/CMakeLists.txt b/src/common/expression/CMakeLists.txt index 1c9679d89aa..9818a38c1ab 100644 --- a/src/common/expression/CMakeLists.txt +++ b/src/common/expression/CMakeLists.txt @@ -31,6 +31,7 @@ nebula_add_library( PredicateExpression.cpp ListComprehensionExpression.cpp ReduceExpression.cpp + MatchPathPatternExpression.cpp ) nebula_add_subdirectory(test) diff --git a/src/common/expression/ExprVisitor.h b/src/common/expression/ExprVisitor.h index c4a079cd706..87c91dc7043 100644 --- a/src/common/expression/ExprVisitor.h +++ b/src/common/expression/ExprVisitor.h @@ -20,6 +20,7 @@ #include "common/expression/LabelExpression.h" #include "common/expression/ListComprehensionExpression.h" #include "common/expression/LogicalExpression.h" +#include "common/expression/MatchPathPatternExpression.h" #include "common/expression/PathBuildExpression.h" #include "common/expression/PredicateExpression.h" #include "common/expression/PropertyExpression.h" @@ -89,6 +90,8 @@ class ExprVisitor { virtual void visit(ReduceExpression *expr) = 0; // subscript range expression virtual void visit(SubscriptRangeExpression *expr) = 0; + // match path pattern expression + virtual void visit(MatchPathPatternExpression *expr) = 0; }; } // namespace nebula diff --git a/src/common/expression/Expression.cpp b/src/common/expression/Expression.cpp index f6cacf218ec..9e10e13a1f6 100644 --- a/src/common/expression/Expression.cpp +++ b/src/common/expression/Expression.cpp @@ -518,6 +518,10 @@ Expression* Expression::decode(ObjectPool* pool, Expression::Decoder& decoder) { case Expression::Kind::kTSFuzzy: { LOG(FATAL) << "Should not decode text search expression"; return exp; + } + case Expression::Kind::kMatchPathPattern: { + LOG(FATAL) << "Should not decode match path pattern expression."; + return exp; } // no default so the compiler will warning when lack } @@ -737,6 +741,9 @@ std::ostream& operator<<(std::ostream& os, Expression::Kind kind) { case Expression::Kind::kReduce: os << "Reduce"; break; + case Expression::Kind::kMatchPathPattern: + os << "MatchPathPattern"; + break; } return os; } diff --git a/src/common/expression/Expression.h b/src/common/expression/Expression.h index 96bb68451d0..0b21287a5fd 100644 --- a/src/common/expression/Expression.h +++ b/src/common/expression/Expression.h @@ -108,6 +108,8 @@ class Expression { kIsNotEmpty, kSubscriptRange, + + kMatchPathPattern, }; Expression(ObjectPool* pool, Kind kind); diff --git a/src/common/expression/MatchPathPatternExpression.cpp b/src/common/expression/MatchPathPatternExpression.cpp new file mode 100644 index 00000000000..7f778f996b1 --- /dev/null +++ b/src/common/expression/MatchPathPatternExpression.cpp @@ -0,0 +1,50 @@ +/* Copyright (c) 2022 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License. + */ + +#include "common/expression/MatchPathPatternExpression.h" + +#include "common/expression/ExprVisitor.h" + +namespace nebula { + +const Value& MatchPathPatternExpression::eval(ExpressionContext& ctx) { + result_ = DCHECK_NOTNULL(prop_)->eval(ctx); + return result_; +} + +bool MatchPathPatternExpression::operator==(const Expression& rhs) const { + if (kind() != rhs.kind()) { + return false; + } + + if (matchPath_ != matchPath_) { + return false; + } + + // The prop_ field is used for evaluation internally, so it don't identify the expression. + // We don't compare it here. + // Ditto for result_ field. + + return true; +} + +std::string MatchPathPatternExpression::toString() const { + return matchPath_->toString(); +} + +void MatchPathPatternExpression::accept(ExprVisitor* visitor) { + visitor->visit(this); +} + +Expression* MatchPathPatternExpression::clone() const { + auto expr = + MatchPathPatternExpression::make(pool_, std::make_unique(matchPath_->clone())); + if (prop_ != nullptr) { + expr->setInputProp(static_cast(prop_->clone())); + } + return expr; +} + +} // namespace nebula diff --git a/src/common/expression/MatchPathPatternExpression.h b/src/common/expression/MatchPathPatternExpression.h new file mode 100644 index 00000000000..c63ce43c31f --- /dev/null +++ b/src/common/expression/MatchPathPatternExpression.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2022 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License. + */ + +#ifndef COMMON_EXPRESSION_MATCHPATHPATTERNEXPRESSION_H_ +#define COMMON_EXPRESSION_MATCHPATHPATTERNEXPRESSION_H_ + +#include "common/expression/Expression.h" +#include "parser/MatchSentence.h" + +namespace nebula { + +// For expression like (v:player)-[e:like]->(p) +// Evaluate to [[v, e, p], [v, e, p]...] +class MatchPathPatternExpression final : public Expression { + public: + MatchPathPatternExpression& operator=(const MatchPathPatternExpression& rhs) = delete; + MatchPathPatternExpression& operator=(MatchPathPatternExpression&&) = delete; + + static MatchPathPatternExpression* make(ObjectPool* pool, + std::unique_ptr&& matchPath) { + return pool->add(new MatchPathPatternExpression(pool, std::move(matchPath))); + } + + const Value& eval(ExpressionContext& ctx) override; + + bool operator==(const Expression& rhs) const override; + + std::string toString() const override; + + void accept(ExprVisitor* visitor) override; + + Expression* clone() const override; + + // Evaluate expression by fetch result from input variable + void setInputProp(const std::string& prop) { + prop_ = InputPropertyExpression::make(pool_, prop); + } + + void setInputProp(InputPropertyExpression* expr) { + prop_ = expr; + } + + InputPropertyExpression* inputProp() const { + return prop_; + } + + private: + explicit MatchPathPatternExpression(ObjectPool* pool, std::unique_ptr&& matchPath) + : Expression(pool, Kind::kMatchPathPattern), matchPath_(std::move(matchPath)) {} + + // This expression contains variable implicitly, so we don't support persist or transform it. + void writeTo(Encoder&) const override { + LOG(FATAL) << "Not implemented"; + } + + // This expression contains variable implicitly, so we don't support persist or transform it. + void resetFrom(Decoder&) override { + LOG(FATAL) << "Not implemented"; + } + + private: + std::unique_ptr matchPath_; + InputPropertyExpression* prop_{ + nullptr}; // The column of input stored the result of the expression + Value result_; +}; +} // namespace nebula +#endif // COMMON_EXPRESSION_MATCHPATHPATTERNEXPRESSION_H_ diff --git a/src/common/expression/test/CMakeLists.txt b/src/common/expression/test/CMakeLists.txt index bab22cb5bc7..f0fc3cb1dfb 100644 --- a/src/common/expression/test/CMakeLists.txt +++ b/src/common/expression/test/CMakeLists.txt @@ -4,7 +4,9 @@ set(expression_test_common_libs $ + $ $ + $ $ $ $ @@ -117,6 +119,7 @@ nebula_add_executable( FunctionCallExpressionBenchmark.cpp OBJECTS $ + $ $ $ $ @@ -140,6 +143,7 @@ nebula_add_executable( AggregateExpressionBenchmark.cpp OBJECTS $ + $ $ $ $ diff --git a/src/common/id/test/CMakeLists.txt b/src/common/id/test/CMakeLists.txt index 347cd19a373..88188f365aa 100644 --- a/src/common/id/test/CMakeLists.txt +++ b/src/common/id/test/CMakeLists.txt @@ -33,6 +33,7 @@ nebula_add_executable( $ $ $ + $ LIBRARIES follybenchmark boost_regex @@ -72,6 +73,7 @@ nebula_add_test( $ $ $ + $ LIBRARIES gtest gtest_main diff --git a/src/common/utils/test/CMakeLists.txt b/src/common/utils/test/CMakeLists.txt index 20b5ad8c40e..d41406d1b6c 100644 --- a/src/common/utils/test/CMakeLists.txt +++ b/src/common/utils/test/CMakeLists.txt @@ -14,6 +14,7 @@ nebula_add_test( $ $ $ + $ $ $ $ @@ -39,6 +40,7 @@ nebula_add_test( $ $ $ + $ $ $ $ @@ -67,6 +69,7 @@ nebula_add_test( $ $ $ + $ $ $ $ diff --git a/src/daemons/CMakeLists.txt b/src/daemons/CMakeLists.txt index 04f6cafd646..9f4ba7f1a29 100644 --- a/src/daemons/CMakeLists.txt +++ b/src/daemons/CMakeLists.txt @@ -26,6 +26,7 @@ set(common_deps $ $ $ + $ $ $ $ @@ -125,6 +126,7 @@ nebula_add_executable( $ $ $ + $ $ $ $ @@ -209,6 +211,7 @@ nebula_add_executable( $ $ $ + $ $ $ $ diff --git a/src/graph/context/test/CMakeLists.txt b/src/graph/context/test/CMakeLists.txt index 70728ad7bde..6cb2e634f99 100644 --- a/src/graph/context/test/CMakeLists.txt +++ b/src/graph/context/test/CMakeLists.txt @@ -6,6 +6,7 @@ SET(CONTEXT_TEST_LIBS $ $ $ + $ $ $ $ @@ -34,6 +35,7 @@ SET(CONTEXT_TEST_LIBS $ $ $ + $ $ $ $ diff --git a/src/graph/executor/test/CMakeLists.txt b/src/graph/executor/test/CMakeLists.txt index 8aa3220c152..0ef0094b1cb 100644 --- a/src/graph/executor/test/CMakeLists.txt +++ b/src/graph/executor/test/CMakeLists.txt @@ -5,6 +5,7 @@ SET(EXEC_QUERY_TEST_OBJS $ $ + $ $ $ $ @@ -39,6 +40,7 @@ SET(EXEC_QUERY_TEST_OBJS $ $ $ + $ $ $ $ diff --git a/src/graph/optimizer/test/CMakeLists.txt b/src/graph/optimizer/test/CMakeLists.txt index f53898b4b9f..d93ba9c6ccb 100644 --- a/src/graph/optimizer/test/CMakeLists.txt +++ b/src/graph/optimizer/test/CMakeLists.txt @@ -7,6 +7,7 @@ set(OPTIMIZER_TEST_LIB $ $ $ + $ $ $ $ @@ -40,6 +41,7 @@ set(OPTIMIZER_TEST_LIB $ $ $ + $ $ $ $ diff --git a/src/graph/planner/test/CMakeLists.txt b/src/graph/planner/test/CMakeLists.txt index d0ca2f81331..579a7eb0c79 100644 --- a/src/graph/planner/test/CMakeLists.txt +++ b/src/graph/planner/test/CMakeLists.txt @@ -21,6 +21,7 @@ nebula_add_test( OBJECTS $ $ + $ $ $ $ @@ -52,6 +53,7 @@ nebula_add_test( $ ${EXEC_PLAN_TEST_FLAG_DEPS} $ + $ $ $ $ diff --git a/src/graph/util/test/CMakeLists.txt b/src/graph/util/test/CMakeLists.txt index 5a1601e0d65..805620705fc 100644 --- a/src/graph/util/test/CMakeLists.txt +++ b/src/graph/util/test/CMakeLists.txt @@ -27,6 +27,7 @@ nebula_add_test( $ $ $ + $ $ $ $ @@ -60,6 +61,7 @@ nebula_add_test( $ $ $ + $ $ $ $ diff --git a/src/graph/validator/test/CMakeLists.txt b/src/graph/validator/test/CMakeLists.txt index f48925ec24d..7df86a09738 100644 --- a/src/graph/validator/test/CMakeLists.txt +++ b/src/graph/validator/test/CMakeLists.txt @@ -17,6 +17,7 @@ set(VALIDATOR_TEST_LIBS $ $ $ + $ $ $ $ diff --git a/src/graph/visitor/DeduceTypeVisitor.cpp b/src/graph/visitor/DeduceTypeVisitor.cpp index 4adb20079d3..73f947d266a 100644 --- a/src/graph/visitor/DeduceTypeVisitor.cpp +++ b/src/graph/visitor/DeduceTypeVisitor.cpp @@ -779,6 +779,11 @@ void DeduceTypeVisitor::visitVertexPropertyExpr(PropertyExpression *expr) { void DeduceTypeVisitor::visit(PathBuildExpression *) { type_ = Value::Type::PATH; } + +void DeduceTypeVisitor::visit(MatchPathPatternExpression *) { + type_ = Value::Type::LIST; +} + #undef DETECT_NARYEXPR_TYPE #undef DETECT_UNARYEXPR_TYPE #undef DETECT_BIEXPR_TYPE diff --git a/src/graph/visitor/DeduceTypeVisitor.h b/src/graph/visitor/DeduceTypeVisitor.h index 688dba6814f..8c665519c6e 100644 --- a/src/graph/visitor/DeduceTypeVisitor.h +++ b/src/graph/visitor/DeduceTypeVisitor.h @@ -91,6 +91,8 @@ class DeduceTypeVisitor final : public ExprVisitor { void visit(ReduceExpression *expr) override; // subscript range void visit(SubscriptRangeExpression *expr) override; + // match path pattern expression + void visit(MatchPathPatternExpression *expr) override; void visitVertexPropertyExpr(PropertyExpression *expr); diff --git a/src/graph/visitor/ExprVisitorImpl.cpp b/src/graph/visitor/ExprVisitorImpl.cpp index f742a7560ca..b2d879d378e 100644 --- a/src/graph/visitor/ExprVisitorImpl.cpp +++ b/src/graph/visitor/ExprVisitorImpl.cpp @@ -200,5 +200,15 @@ void ExprVisitorImpl::visit(SubscriptRangeExpression *expr) { } } +void ExprVisitorImpl::visit(MatchPathPatternExpression *expr) { + DCHECK(ok()) << expr->toString(); + if (expr->inputProp() != nullptr) { + expr->inputProp()->accept(this); + if (!ok()) { + return; + } + } +} + } // namespace graph } // namespace nebula diff --git a/src/graph/visitor/ExprVisitorImpl.h b/src/graph/visitor/ExprVisitorImpl.h index 8154207a8a9..641bd0da2cf 100644 --- a/src/graph/visitor/ExprVisitorImpl.h +++ b/src/graph/visitor/ExprVisitorImpl.h @@ -41,6 +41,8 @@ class ExprVisitorImpl : public ExprVisitor { void visit(ReduceExpression *expr) override; // subscript range expression void visit(SubscriptRangeExpression *expr) override; + // match path pattern expression + void visit(MatchPathPatternExpression *expr) override; protected: using ExprVisitor::visit; diff --git a/src/graph/visitor/FoldConstantExprVisitor.cpp b/src/graph/visitor/FoldConstantExprVisitor.cpp index fbef39e32bb..30cadcf8b25 100644 --- a/src/graph/visitor/FoldConstantExprVisitor.cpp +++ b/src/graph/visitor/FoldConstantExprVisitor.cpp @@ -527,5 +527,9 @@ void FoldConstantExprVisitor::visit(SubscriptRangeExpression *expr) { canBeFolded_ = canBeFolded; } +void FoldConstantExprVisitor::visit(MatchPathPatternExpression *) { + canBeFolded_ = false; +} + } // namespace graph } // namespace nebula diff --git a/src/graph/visitor/FoldConstantExprVisitor.h b/src/graph/visitor/FoldConstantExprVisitor.h index a5ab4c31fe4..ded56d8eb1e 100644 --- a/src/graph/visitor/FoldConstantExprVisitor.h +++ b/src/graph/visitor/FoldConstantExprVisitor.h @@ -82,6 +82,8 @@ class FoldConstantExprVisitor final : public ExprVisitor { void visit(ReduceExpression *expr) override; // subscript range expression void visit(SubscriptRangeExpression *expr) override; + // match path pattern expression + void visit(MatchPathPatternExpression *expr) override; void visitBinaryExpr(BinaryExpression *expr); Expression *fold(Expression *expr); diff --git a/src/graph/visitor/RewriteSymExprVisitor.cpp b/src/graph/visitor/RewriteSymExprVisitor.cpp index 214aaf621b0..9925ac2e718 100644 --- a/src/graph/visitor/RewriteSymExprVisitor.cpp +++ b/src/graph/visitor/RewriteSymExprVisitor.cpp @@ -336,5 +336,18 @@ void RewriteSymExprVisitor::visit(SubscriptRangeExpression *expr) { } } +void RewriteSymExprVisitor::visit(MatchPathPatternExpression *expr) { + if (expr->inputProp() != nullptr) { + expr->inputProp()->accept(this); + if (expr_) { + if (expr_->kind() != Expression::Kind::kInputProperty) { + hasWrongType_ = true; + return; + } + expr->setInputProp(static_cast(expr_)); + } + } +} + } // namespace graph } // namespace nebula diff --git a/src/graph/visitor/RewriteSymExprVisitor.h b/src/graph/visitor/RewriteSymExprVisitor.h index 3ff63445072..4a45a2f11a9 100644 --- a/src/graph/visitor/RewriteSymExprVisitor.h +++ b/src/graph/visitor/RewriteSymExprVisitor.h @@ -79,6 +79,8 @@ class RewriteSymExprVisitor final : public ExprVisitor { void visit(ReduceExpression *expr) override; // subscript range expression void visit(SubscriptRangeExpression *expr) override; + // match path pattern expression + void visit(MatchPathPatternExpression *expr) override; private: void visitBinaryExpr(BinaryExpression *expr); diff --git a/src/graph/visitor/VidExtractVisitor.cpp b/src/graph/visitor/VidExtractVisitor.cpp index ed54a9c8aa4..179abcf8824 100644 --- a/src/graph/visitor/VidExtractVisitor.cpp +++ b/src/graph/visitor/VidExtractVisitor.cpp @@ -472,6 +472,11 @@ void VidExtractVisitor::visit(SubscriptRangeExpression *expr) { vidPattern_ = VidPattern{}; } +void VidExtractVisitor::visit(MatchPathPatternExpression *expr) { + UNUSED(expr); + vidPattern_ = VidPattern{}; +} + std::ostream &operator<<(std::ostream &os, const VidExtractVisitor::VidPattern &vp) { switch (vp.spec) { case VidExtractVisitor::VidPattern::Special::kIgnore: diff --git a/src/graph/visitor/VidExtractVisitor.h b/src/graph/visitor/VidExtractVisitor.h index 82df3f2eb0e..3145d45cd8c 100644 --- a/src/graph/visitor/VidExtractVisitor.h +++ b/src/graph/visitor/VidExtractVisitor.h @@ -103,6 +103,8 @@ class VidExtractVisitor final : public ExprVisitor { void visit(ReduceExpression *expr) override; // subscript range expression void visit(SubscriptRangeExpression *expr) override; + // match path pattern expression + void visit(MatchPathPatternExpression *expr) override; private: void visitBinaryExpr(BinaryExpression *expr); diff --git a/src/graph/visitor/test/CMakeLists.txt b/src/graph/visitor/test/CMakeLists.txt index a284730e322..f37902a9543 100644 --- a/src/graph/visitor/test/CMakeLists.txt +++ b/src/graph/visitor/test/CMakeLists.txt @@ -34,6 +34,7 @@ nebula_add_test( $ ${EXPR_FLAG_DEPS} $ + $ $ $ $ diff --git a/src/kvstore/test/CMakeLists.txt b/src/kvstore/test/CMakeLists.txt index 1954c2c9f0d..6b290ef5cdc 100644 --- a/src/kvstore/test/CMakeLists.txt +++ b/src/kvstore/test/CMakeLists.txt @@ -26,6 +26,7 @@ set(KVSTORE_TEST_LIBS $ $ $ + $ $ $ $ diff --git a/src/meta/CMakeLists.txt b/src/meta/CMakeLists.txt index c2b3b30af90..342b60fef16 100644 --- a/src/meta/CMakeLists.txt +++ b/src/meta/CMakeLists.txt @@ -152,6 +152,7 @@ set(meta_test_deps $ $ $ + $ $ $ $ diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt index fc2f7d4d2b3..2e8b67e33f3 100644 --- a/src/parser/CMakeLists.txt +++ b/src/parser/CMakeLists.txt @@ -43,4 +43,9 @@ nebula_add_library( MatchSentence.cpp ) +nebula_add_library( + ast_match_path_obj OBJECT + MatchPath.cpp +) + nebula_add_subdirectory(test) diff --git a/src/parser/MatchPath.cpp b/src/parser/MatchPath.cpp new file mode 100644 index 00000000000..9731f12067c --- /dev/null +++ b/src/parser/MatchPath.cpp @@ -0,0 +1,108 @@ +/* Copyright (c) 2022 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License. + */ + +#include "parser/MatchPath.h" + +namespace nebula { + +std::string MatchStepRange::toString() const { + return folly::stringPrintf("%lu..%lu", min(), max()); +} + +std::string MatchEdge::toString() const { + std::string buf; + buf.reserve(256); + + std::string end; + if (direction_ == Direction::OUT_EDGE) { + buf += '-'; + end = "->"; + } else if (direction_ == Direction::IN_EDGE) { + buf += "<-"; + end = "-"; + } else { + buf += '-'; + end = "-"; + } + + if (!alias_.empty() || !types_.empty() || range_ != nullptr || props_ != nullptr) { + buf += '['; + if (!alias_.empty()) { + buf += alias_; + } + if (!types_.empty()) { + buf += ':'; + buf += *types_[0]; + for (auto i = 1u; i < types_.size(); i++) { + buf += "|"; + buf += *types_[i]; + } + } + if (range_ != nullptr) { + buf += "*"; + if (range_->min() == range_->max()) { + buf += folly::to(range_->min()); + } else if (range_->max() == std::numeric_limits::max()) { + if (range_->min() != 1) { + buf += folly::to(range_->min()); + buf += ".."; + } + } else { + if (range_->min() != 1) { + buf += folly::to(range_->min()); + } + buf += ".."; + buf += folly::to(range_->max()); + } + } + if (props_ != nullptr) { + buf += props_->toString(); + } + buf += ']'; + } + + buf += end; + + return buf; +} + +std::string MatchNode::toString() const { + std::string buf; + buf.reserve(64); + + buf += '('; + if (!alias_.empty()) { + buf += alias_; + } + if (labels_ != nullptr) { + buf += labels_->toString(); + } + if (props_ != nullptr) { + buf += props_->toString(); + } + buf += ')'; + + return buf; +} + +std::string MatchPath::toString() const { + std::string buf; + buf.reserve(256); + + if (alias_ != nullptr) { + buf += *alias_; + buf += " = "; + } + + buf += node(0)->toString(); + for (auto i = 0u; i < edges_.size(); i++) { + buf += edge(i)->toString(); + buf += node(i + 1)->toString(); + } + + return buf; +} + +} // namespace nebula diff --git a/src/parser/MatchPath.h b/src/parser/MatchPath.h new file mode 100644 index 00000000000..2322ba45bc2 --- /dev/null +++ b/src/parser/MatchPath.h @@ -0,0 +1,319 @@ +/* Copyright (c) 2022 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License. + */ +#ifndef PARSER_MATCHPATH_H_ +#define PARSER_MATCHPATH_H_ + +#include +#include +#include + +#include "common/expression/ContainerExpression.h" +#include "interface/gen-cpp2/storage_types.h" + +namespace nebula { + +class MatchEdgeTypeList final { + public: + MatchEdgeTypeList() = default; + + void add(std::string* item) { + items_.emplace_back(item); + } + + auto items() && { + return std::move(items_); + } + + private: + std::vector> items_; +}; + +class MatchStepRange final { + public: + explicit MatchStepRange(size_t min = 0, size_t max = std::numeric_limits::max()) { + min_ = min; + max_ = max; + } + + auto min() const { + return min_; + } + + auto max() const { + return max_; + } + + std::string toString() const; + + private: + size_t min_{1}; + size_t max_{1}; +}; + +class MatchEdgeProp final { + public: + MatchEdgeProp(const std::string& alias, + MatchEdgeTypeList* types, + MatchStepRange* range, + Expression* props = nullptr) { + alias_ = alias; + range_.reset(range); + props_ = static_cast(props); + if (types != nullptr) { + types_ = std::move(*types).items(); + delete types; + } + } + + auto get() && { + return std::make_tuple( + std::move(alias_), std::move(types_), std::move(range_), std::move(props_)); + } + + private: + std::string alias_; + std::vector> types_; + MapExpression* props_{nullptr}; + std::unique_ptr range_; +}; + +class MatchEdge final { + public: + using Direction = nebula::storage::cpp2::EdgeDirection; + MatchEdge(MatchEdgeProp* prop, Direction direction) { + if (prop != nullptr) { + auto tuple = std::move(*prop).get(); + alias_ = std::move(std::get<0>(tuple)); + types_ = std::move(std::get<1>(tuple)); + range_ = std::move(std::get<2>(tuple)); + props_ = std::move(std::get<3>(tuple)); + delete prop; + } + direction_ = direction; + } + MatchEdge() = default; + + auto direction() const { + return direction_; + } + + const std::string& alias() const { + return alias_; + } + + auto& types() const { + return types_; + } + + const MapExpression* props() const { + return props_; + } + + auto* range() const { + return range_.get(); + } + + std::string toString() const; + + MatchEdge clone() const { + auto me = MatchEdge(); + me.direction_ = direction_; + me.alias_ = alias_; + for (const auto& type : types_) { + me.types_.emplace_back(std::make_unique(*type)); + } + if (range_ != nullptr) { + me.range_ = std::make_unique(*range_); + } + me.props_ = props_; + return me; + } + + private: + Direction direction_; + std::string alias_; + std::vector> types_; + std::unique_ptr range_; + MapExpression* props_{nullptr}; +}; + +class MatchNodeLabel final { + public: + explicit MatchNodeLabel(std::string* label, Expression* props = nullptr) + : label_(label), props_(static_cast(props)) { + DCHECK(props == nullptr || props->kind() == Expression::Kind::kMap); + } + MatchNodeLabel() = default; + + const std::string* label() const { + return label_.get(); + } + + const MapExpression* props() const { + return props_; + } + + MapExpression* props() { + return props_; + } + + std::string toString() const { + std::stringstream ss; + ss << ":" << *label_; + if (props_ != nullptr) { + ss << props_->toString(); + } + return ss.str(); + } + + MatchNodeLabel clone() const { + auto mnl = MatchNodeLabel(); + if (label_ != nullptr) { + mnl.label_ = std::make_unique(*label_); + } + mnl.props_ = props_; + return mnl; + } + + private: + std::unique_ptr label_; + MapExpression* props_{nullptr}; +}; + +class MatchNodeLabelList final { + public: + void add(MatchNodeLabel* label) { + labels_.emplace_back(label); + } + + const auto& labels() const { + return labels_; + } + + std::string toString() const { + std::stringstream ss; + for (const auto& label : labels_) { + ss << label->toString(); + } + return ss.str(); + } + + MatchNodeLabelList clone() const { + MatchNodeLabelList ret; + for (const auto& label : labels_) { + ret.labels_.emplace_back(std::make_unique(label->clone())); + } + return ret; + } + + private: + std::vector> labels_; +}; + +class MatchNode final { + public: + MatchNode(const std::string& alias, MatchNodeLabelList* labels, Expression* props = nullptr) { + alias_ = alias; + labels_.reset(labels); + props_ = static_cast(props); + } + MatchNode() = default; + + const std::string& alias() const { + return alias_; + } + + const auto* labels() const { + return labels_.get(); + } + + const MapExpression* props() const { + return props_; + } + + MapExpression* props() { + return props_; + } + + std::string toString() const; + + MatchNode clone() const { + auto me = MatchNode(); + me.alias_ = alias_; + if (labels_ != nullptr) { + me.labels_ = std::make_unique(labels_->clone()); + } + me.props_ = props_; + return me; + } + + private: + std::string alias_; + std::unique_ptr labels_; + MapExpression* props_{nullptr}; +}; + +class MatchPath final { + public: + MatchPath() = default; + explicit MatchPath(MatchNode* node) { + nodes_.emplace_back(node); + } + + void add(MatchEdge* edge, MatchNode* node) { + edges_.emplace_back(edge); + nodes_.emplace_back(node); + } + + void setAlias(std::string* alias) { + alias_.reset(alias); + } + + const std::string* alias() const { + return alias_.get(); + } + + const auto& nodes() const { + return nodes_; + } + + const auto& edges() const { + return edges_; + } + + size_t steps() const { + return edges_.size(); + } + + const MatchNode* node(size_t i) const { + return nodes_[i].get(); + } + + const MatchEdge* edge(size_t i) const { + return edges_[i].get(); + } + + std::string toString() const; + + MatchPath clone() const { + auto path = MatchPath(); + if (alias_ != nullptr) { + path.setAlias(new std::string(*alias_)); + } + for (std::size_t i = 0; i < nodes_.size(); ++i) { + path.add(new MatchEdge(edges_[i]->clone()), new MatchNode(nodes_[i]->clone())); + } + return path; + } + + private: + std::unique_ptr alias_; + std::vector> nodes_; + std::vector> edges_; +}; + +} // namespace nebula + +#endif // PARSER_MATCHPATH_H_ diff --git a/src/parser/MatchSentence.cpp b/src/parser/MatchSentence.cpp index 31db8e7e480..9ff07e88d0d 100644 --- a/src/parser/MatchSentence.cpp +++ b/src/parser/MatchSentence.cpp @@ -7,10 +7,6 @@ namespace nebula { -std::string MatchStepRange::toString() const { - return folly::stringPrintf("%lu..%lu", min(), max()); -} - std::string MatchClause::toString() const { std::string buf; buf.reserve(256); @@ -78,100 +74,6 @@ std::string WithClause::toString() const { return buf; } -std::string MatchEdge::toString() const { - std::string buf; - buf.reserve(256); - - std::string end; - if (direction_ == Direction::OUT_EDGE) { - buf += '-'; - end = "->"; - } else if (direction_ == Direction::IN_EDGE) { - buf += "<-"; - end = "-"; - } else { - buf += '-'; - end = "-"; - } - - if (!alias_.empty() || !types_.empty() || range_ != nullptr || props_ != nullptr) { - buf += '['; - if (!alias_.empty()) { - buf += alias_; - } - if (!types_.empty()) { - buf += ':'; - buf += *types_[0]; - for (auto i = 1u; i < types_.size(); i++) { - buf += "|"; - buf += *types_[i]; - } - } - if (range_ != nullptr) { - buf += "*"; - if (range_->min() == range_->max()) { - buf += folly::to(range_->min()); - } else if (range_->max() == std::numeric_limits::max()) { - if (range_->min() != 1) { - buf += folly::to(range_->min()); - buf += ".."; - } - } else { - if (range_->min() != 1) { - buf += folly::to(range_->min()); - } - buf += ".."; - buf += folly::to(range_->max()); - } - } - if (props_ != nullptr) { - buf += props_->toString(); - } - buf += ']'; - } - - buf += end; - - return buf; -} - -std::string MatchNode::toString() const { - std::string buf; - buf.reserve(64); - - buf += '('; - if (!alias_.empty()) { - buf += alias_; - } - if (labels_ != nullptr) { - buf += labels_->toString(); - } - if (props_ != nullptr) { - buf += props_->toString(); - } - buf += ')'; - - return buf; -} - -std::string MatchPath::toString() const { - std::string buf; - buf.reserve(256); - - if (alias_ != nullptr) { - buf += *alias_; - buf += " = "; - } - - buf += node(0)->toString(); - for (auto i = 0u; i < edges_.size(); i++) { - buf += edge(i)->toString(); - buf += node(i + 1)->toString(); - } - - return buf; -} - std::string MatchReturnItems::toString() const { std::string buf; if (allNamedAliases_) { diff --git a/src/parser/MatchSentence.h b/src/parser/MatchSentence.h index 4fa7619b95f..9969e8645da 100644 --- a/src/parser/MatchSentence.h +++ b/src/parser/MatchSentence.h @@ -8,256 +8,12 @@ #include "common/expression/ContainerExpression.h" #include "common/expression/SubscriptExpression.h" -#include "parser/Clauses.h" +#include "parser/MatchPath.h" #include "parser/Sentence.h" #include "parser/TraverseSentences.h" namespace nebula { -class MatchEdgeTypeList final { - public: - MatchEdgeTypeList() = default; - - void add(std::string* item) { - items_.emplace_back(item); - } - - auto items() && { - return std::move(items_); - } - - private: - std::vector> items_; -}; - -class MatchStepRange final { - public: - explicit MatchStepRange(size_t min = 0, size_t max = std::numeric_limits::max()) { - min_ = min; - max_ = max; - } - - auto min() const { - return min_; - } - - auto max() const { - return max_; - } - - std::string toString() const; - - private: - size_t min_{1}; - size_t max_{1}; -}; - -class MatchEdgeProp final { - public: - MatchEdgeProp(const std::string& alias, - MatchEdgeTypeList* types, - MatchStepRange* range, - Expression* props = nullptr) { - alias_ = alias; - range_.reset(range); - props_ = static_cast(props); - if (types != nullptr) { - types_ = std::move(*types).items(); - delete types; - } - } - - auto get() && { - return std::make_tuple( - std::move(alias_), std::move(types_), std::move(range_), std::move(props_)); - } - - private: - std::string alias_; - std::vector> types_; - MapExpression* props_{nullptr}; - std::unique_ptr range_; -}; - -class MatchEdge final { - public: - using Direction = nebula::storage::cpp2::EdgeDirection; - MatchEdge(MatchEdgeProp* prop, Direction direction) { - if (prop != nullptr) { - auto tuple = std::move(*prop).get(); - alias_ = std::move(std::get<0>(tuple)); - types_ = std::move(std::get<1>(tuple)); - range_ = std::move(std::get<2>(tuple)); - props_ = std::move(std::get<3>(tuple)); - delete prop; - } - direction_ = direction; - } - - auto direction() const { - return direction_; - } - - const std::string& alias() const { - return alias_; - } - - auto& types() const { - return types_; - } - - const MapExpression* props() const { - return props_; - } - - auto* range() const { - return range_.get(); - } - - std::string toString() const; - - private: - Direction direction_; - std::string alias_; - std::vector> types_; - std::unique_ptr range_; - MapExpression* props_{nullptr}; -}; - -class MatchNodeLabel final { - public: - explicit MatchNodeLabel(std::string* label, Expression* props = nullptr) - : label_(label), props_(static_cast(props)) { - DCHECK(props == nullptr || props->kind() == Expression::Kind::kMap); - } - - const std::string* label() const { - return label_.get(); - } - - const MapExpression* props() const { - return props_; - } - - MapExpression* props() { - return props_; - } - - std::string toString() const { - std::stringstream ss; - ss << ":" << *label_; - if (props_ != nullptr) { - ss << props_->toString(); - } - return ss.str(); - } - - private: - std::unique_ptr label_; - MapExpression* props_{nullptr}; -}; - -class MatchNodeLabelList final { - public: - void add(MatchNodeLabel* label) { - labels_.emplace_back(label); - } - - const auto& labels() const { - return labels_; - } - - std::string toString() const { - std::stringstream ss; - for (const auto& label : labels_) { - ss << label->toString(); - } - return ss.str(); - } - - private: - std::vector> labels_; -}; - -class MatchNode final { - public: - MatchNode(const std::string& alias, MatchNodeLabelList* labels, Expression* props = nullptr) { - alias_ = alias; - labels_.reset(labels); - props_ = static_cast(props); - } - - const std::string& alias() const { - return alias_; - } - - const auto* labels() const { - return labels_.get(); - } - - const MapExpression* props() const { - return props_; - } - - MapExpression* props() { - return props_; - } - - std::string toString() const; - - private: - std::string alias_; - std::unique_ptr labels_; - MapExpression* props_{nullptr}; -}; - -class MatchPath final { - public: - explicit MatchPath(MatchNode* node) { - nodes_.emplace_back(node); - } - - void add(MatchEdge* edge, MatchNode* node) { - edges_.emplace_back(edge); - nodes_.emplace_back(node); - } - - void setAlias(std::string* alias) { - alias_.reset(alias); - } - - const std::string* alias() const { - return alias_.get(); - } - - const auto& nodes() const { - return nodes_; - } - - const auto& edges() const { - return edges_; - } - - size_t steps() const { - return edges_.size(); - } - - const MatchNode* node(size_t i) const { - return nodes_[i].get(); - } - - const MatchEdge* edge(size_t i) const { - return edges_[i].get(); - } - - std::string toString() const; - - private: - std::unique_ptr alias_; - std::vector> nodes_; - std::vector> edges_; -}; - class MatchPathList final { public: explicit MatchPathList(MatchPath* path); diff --git a/src/parser/parser.yy b/src/parser/parser.yy index bac8849b2e9..8ee8cce4cee 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -250,6 +250,7 @@ static constexpr size_t kCommentLengthLimit = 256; %type text_search_expression %type constant_expression %type query_unique_identifier_value +%type match_path_pattern_expression %type argument_list opt_argument_list %type geo_shape_type %type type_spec @@ -702,6 +703,9 @@ expression_internal | uuid_expression { $$ = $1; } + | match_path_pattern_expression { + $$ = $1; + } ; constant_expression @@ -1118,6 +1122,12 @@ uuid_expression } ; +match_path_pattern_expression + : match_path_pattern { + $$ = MatchPathPatternExpression::make(qctx->objPool(), std::unique_ptr($1)); + } + ; + opt_argument_list : %empty { $$ = ArgumentList::make(qctx->objPool()); diff --git a/src/parser/test/CMakeLists.txt b/src/parser/test/CMakeLists.txt index 0b689c5568b..7bf3596ab73 100644 --- a/src/parser/test/CMakeLists.txt +++ b/src/parser/test/CMakeLists.txt @@ -4,6 +4,7 @@ set(PARSER_TEST_LIBS $ + $ $ $ $ diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index 7f0422cdf86..6f139423da3 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -2776,6 +2776,24 @@ TEST_F(ParserTest, MatchListSubscriptRange) { } } +TEST_F(ParserTest, MatchPathPatternExpression) { + { + std::string query = "WITH ()-[:like]->() AS l RETURN l"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "RETURN (v:player)-[:like*0..2]->() AS l"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "UNWIND (v)-[]->(v) AS l RETURN l"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } +} + TEST_F(ParserTest, HOST) { { std::string query = "ADD HOSTS 127.0.0.1:8989"; diff --git a/src/storage/ExprVisitorBase.cpp b/src/storage/ExprVisitorBase.cpp index 5927745b3ea..8d8b21ec603 100644 --- a/src/storage/ExprVisitorBase.cpp +++ b/src/storage/ExprVisitorBase.cpp @@ -144,5 +144,9 @@ void ExprVisitorBase::visit(SubscriptRangeExpression *expr) { fatal(expr); } +void ExprVisitorBase::visit(MatchPathPatternExpression *expr) { + fatal(expr); +} + } // namespace storage } // namespace nebula diff --git a/src/storage/ExprVisitorBase.h b/src/storage/ExprVisitorBase.h index 7134447eb13..4d4975be4fa 100644 --- a/src/storage/ExprVisitorBase.h +++ b/src/storage/ExprVisitorBase.h @@ -62,6 +62,8 @@ class ExprVisitorBase : public ::nebula::ExprVisitor { void visit(ReduceExpression *expr) override; // subscript range expression void visit(SubscriptRangeExpression *expr) override; + // match pattern expression + void visit(MatchPathPatternExpression *expr) override; private: using ::nebula::ExprVisitor::visit; diff --git a/src/storage/query/QueryBaseProcessor-inl.h b/src/storage/query/QueryBaseProcessor-inl.h index 6753f8f898c..d87e2b32120 100644 --- a/src/storage/query/QueryBaseProcessor-inl.h +++ b/src/storage/query/QueryBaseProcessor-inl.h @@ -599,7 +599,8 @@ nebula::cpp2::ErrorCode QueryBaseProcessor::checkExp(const Expression case Expression::Kind::kTSFuzzy: case Expression::Kind::kAggregate: case Expression::Kind::kSubscriptRange: - case Expression::Kind::kVersionedVar: { + case Expression::Kind::kVersionedVar: + case Expression::Kind::kMatchPathPattern: { LOG(ERROR) << "Unimplemented expression type! kind = " << exp->kind(); return nebula::cpp2::ErrorCode::E_INVALID_FILTER; } diff --git a/src/storage/test/CMakeLists.txt b/src/storage/test/CMakeLists.txt index 5bbbf05acb3..5810bf61560 100644 --- a/src/storage/test/CMakeLists.txt +++ b/src/storage/test/CMakeLists.txt @@ -45,6 +45,7 @@ set(storage_test_deps $ $ $ + $ $ $ $ diff --git a/src/tools/db-dump/CMakeLists.txt b/src/tools/db-dump/CMakeLists.txt index 9eb9c671658..66084aa6ef3 100644 --- a/src/tools/db-dump/CMakeLists.txt +++ b/src/tools/db-dump/CMakeLists.txt @@ -43,6 +43,7 @@ set(tools_test_deps $ $ $ + $ $ $ $ diff --git a/src/tools/db-upgrade/CMakeLists.txt b/src/tools/db-upgrade/CMakeLists.txt index 367918cb540..29ea63b0755 100644 --- a/src/tools/db-upgrade/CMakeLists.txt +++ b/src/tools/db-upgrade/CMakeLists.txt @@ -52,6 +52,7 @@ nebula_add_executable( $ $ $ + $ $ $ $ diff --git a/src/tools/meta-dump/CMakeLists.txt b/src/tools/meta-dump/CMakeLists.txt index 7ba2307dcb0..fbbe2c4b30f 100644 --- a/src/tools/meta-dump/CMakeLists.txt +++ b/src/tools/meta-dump/CMakeLists.txt @@ -48,6 +48,7 @@ nebula_add_executable( $ $ $ + $ $ $ $ diff --git a/src/tools/simple-kv-verify/CMakeLists.txt b/src/tools/simple-kv-verify/CMakeLists.txt index 8434a6c8104..1d752a3f671 100644 --- a/src/tools/simple-kv-verify/CMakeLists.txt +++ b/src/tools/simple-kv-verify/CMakeLists.txt @@ -47,6 +47,7 @@ nebula_add_executable( $ $ $ + $ $ $ $ diff --git a/src/tools/storage-perf/CMakeLists.txt b/src/tools/storage-perf/CMakeLists.txt index 40a34abfa48..2e85f342958 100644 --- a/src/tools/storage-perf/CMakeLists.txt +++ b/src/tools/storage-perf/CMakeLists.txt @@ -43,6 +43,7 @@ set(perf_test_deps $ $ $ + $ $ $ $ From be9a789f013af4df8d0b0bc42a92bf4b072c30fe Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Thu, 24 Feb 2022 16:28:46 +0800 Subject: [PATCH 2/7] Change to relationship pattern. --- src/parser/parser.yy | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 8ee8cce4cee..065abe2cf35 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -312,7 +312,7 @@ static constexpr size_t kCommentLengthLimit = 256; %type case_condition %type case_default -%type match_path_pattern +%type match_path_pattern match_relationship_pattern %type match_path %type match_path_list %type match_node @@ -1123,7 +1123,7 @@ uuid_expression ; match_path_pattern_expression - : match_path_pattern { + : match_relationship_pattern { $$ = MatchPathPatternExpression::make(qctx->objPool(), std::unique_ptr($1)); } ; @@ -1715,6 +1715,17 @@ match_sentence } ; +match_relationship_pattern + : match_node match_edge match_node { + $$ = new MatchPath($1); + $$->add($2, $3); + } + | match_relationship_pattern match_edge match_node { + $$ = $1; + $$->add($2, $3); + } + ; + match_path_pattern : match_node { $$ = new MatchPath($1); From c2a7cb8476e41c8a8b77e3b435c04ab1815d725f Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Thu, 24 Feb 2022 17:47:47 +0800 Subject: [PATCH 3/7] Fix typo. --- src/parser/CMakeLists.txt | 4 ++-- src/parser/parser.yy | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt index 2e8b67e33f3..4895f68d2a2 100644 --- a/src/parser/CMakeLists.txt +++ b/src/parser/CMakeLists.txt @@ -6,13 +6,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(ENABLE_ERROR) if(ENABLE_VERBOSE_BISON) - set(bison_flags "-Werror -v") + set(bison_flags "-Werror -v -Wcex") else() set(bison_flags "-Werror") endif() else() if(ENABLE_VERBOSE_BISON) - set(bison_flags "-v") + set(bison_flags "-v -Wcex") else() set(bison_flags "") endif() diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 065abe2cf35..d2fbfacda87 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -312,7 +312,7 @@ static constexpr size_t kCommentLengthLimit = 256; %type case_condition %type case_default -%type match_path_pattern match_relationship_pattern +%type match_path_pattern match_relationships_pattern %type match_path %type match_path_list %type match_node @@ -1123,7 +1123,7 @@ uuid_expression ; match_path_pattern_expression - : match_relationship_pattern { + : match_relationships_pattern { $$ = MatchPathPatternExpression::make(qctx->objPool(), std::unique_ptr($1)); } ; @@ -1715,12 +1715,12 @@ match_sentence } ; -match_relationship_pattern +match_relationships_pattern : match_node match_edge match_node { $$ = new MatchPath($1); $$->add($2, $3); } - | match_relationship_pattern match_edge match_node { + | match_relationships_pattern match_edge match_node { $$ = $1; $$->add($2, $3); } From 63ff6cce8a3b96e0da4c188a9facc8dec42e6237 Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Wed, 2 Mar 2022 16:02:38 +0800 Subject: [PATCH 4/7] Resolve shift/reduce conflict by precedence. --- src/parser/parser.yy | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/parser/parser.yy b/src/parser/parser.yy index d2fbfacda87..12814cdef15 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -408,9 +408,12 @@ static constexpr size_t kCommentLengthLimit = 256; %left KW_AND %right KW_NOT %left EQ NE LT LE GT GE REG KW_IN KW_NOT_IN KW_CONTAINS KW_NOT_CONTAINS KW_STARTS_WITH KW_ENDS_WITH KW_NOT_STARTS_WITH KW_NOT_ENDS_WITH KW_IS_NULL KW_IS_NOT_NULL KW_IS_EMPTY KW_IS_NOT_EMPTY +%nonassoc DUMMY_LOWER_THAN_MINUS %left PLUS MINUS %left STAR DIV MOD %right NOT +%nonassoc DUMMY_LOWER_THAN_L_BRACE +%nonassoc L_BRACE KW_MAP %nonassoc UNARY_PLUS %nonassoc UNARY_MINUS %nonassoc CASTING @@ -1123,7 +1126,7 @@ uuid_expression ; match_path_pattern_expression - : match_relationships_pattern { + : match_relationships_pattern %prec DUMMY_LOWER_THAN_MINUS { $$ = MatchPathPatternExpression::make(qctx->objPool(), std::unique_ptr($1)); } ; @@ -1791,7 +1794,7 @@ match_node_label_list ; match_alias - : %empty { + : %empty %prec DUMMY_LOWER_THAN_L_BRACE { $$ = new std::string(); } | name_label { From 54c8af4f3b016eea5e97453763532df5a4876c52 Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Wed, 2 Mar 2022 17:59:47 +0800 Subject: [PATCH 5/7] Resolve reduce/reduce conflict. --- src/parser/parser.yy | 41 +++++++++++-------- src/parser/test/ParserTest.cpp | 5 +++ tests/tck/features/match/Base.feature | 9 ++++ tests/tck/features/yield/yield.IntVid.feature | 4 +- tests/tck/features/yield/yield.feature | 4 +- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 12814cdef15..03514a19475 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -324,7 +324,6 @@ static constexpr size_t kCommentLengthLimit = 256; %type match_return %type match_skip %type match_limit -%type match_alias %type match_edge_type_list %type opt_match_edge_type_list %type unwind_clause with_clause match_clause reading_clause @@ -414,6 +413,8 @@ static constexpr size_t kCommentLengthLimit = 256; %right NOT %nonassoc DUMMY_LOWER_THAN_L_BRACE %nonassoc L_BRACE KW_MAP +%nonassoc DUMMY_LOWER_THAN_R_PAREN +%nonassoc R_PAREN %nonassoc UNARY_PLUS %nonassoc UNARY_MINUS %nonassoc CASTING @@ -575,7 +576,7 @@ expression_internal : constant_expression { $$ = $1; } - | name_label { + | name_label %prec DUMMY_LOWER_THAN_R_PAREN { $$ = LabelExpression::make(qctx->objPool(), *$1); delete $1; } @@ -1272,7 +1273,7 @@ container_expression | set_expression { $$ = $1; } - | map_expression { + | map_expression %prec DUMMY_LOWER_THAN_R_PAREN { $$ = $1; } ; @@ -1759,18 +1760,27 @@ match_path_list } match_node - : L_PAREN match_alias R_PAREN { + : L_PAREN name_label R_PAREN { $$ = new MatchNode(*$2, nullptr, nullptr); delete $2; } - | L_PAREN match_alias match_node_label_list R_PAREN { + | L_PAREN name_label match_node_label_list R_PAREN { $$ = new MatchNode(*$2, $3, nullptr); delete $2; } - | L_PAREN match_alias map_expression R_PAREN { + | L_PAREN name_label map_expression R_PAREN { $$ = new MatchNode(*$2, nullptr, $3); delete $2; } + | L_PAREN R_PAREN %prec DUMMY_LOWER_THAN_L_BRACE { + $$ = new MatchNode("", nullptr, nullptr); + } + | L_PAREN match_node_label_list R_PAREN %prec DUMMY_LOWER_THAN_L_BRACE { + $$ = new MatchNode("", $2, nullptr); + } + | L_PAREN map_expression R_PAREN %prec DUMMY_LOWER_THAN_L_BRACE { + $$ = new MatchNode("", nullptr, $2); + } ; match_node_label @@ -1793,15 +1803,6 @@ match_node_label_list } ; -match_alias - : %empty %prec DUMMY_LOWER_THAN_L_BRACE { - $$ = new std::string(); - } - | name_label { - $$ = $1; - } - ; - match_edge : MINUS match_edge_prop MINUS { $$ = new MatchEdge($2, storage::cpp2::EdgeDirection::BOTH); @@ -1821,14 +1822,20 @@ match_edge_prop : %empty { $$ = nullptr; } - | L_BRACKET match_alias opt_match_edge_type_list match_step_range R_BRACKET { + | L_BRACKET name_label opt_match_edge_type_list match_step_range R_BRACKET { $$ = new MatchEdgeProp(*$2, $3, $4, nullptr); delete $2; } - | L_BRACKET match_alias opt_match_edge_type_list match_step_range map_expression R_BRACKET { + | L_BRACKET name_label opt_match_edge_type_list match_step_range map_expression R_BRACKET { $$ = new MatchEdgeProp(*$2, $3, $4, $5); delete $2; } + | L_BRACKET opt_match_edge_type_list match_step_range R_BRACKET { + $$ = new MatchEdgeProp("", $2, $3, nullptr); + } + | L_BRACKET opt_match_edge_type_list match_step_range map_expression R_BRACKET { + $$ = new MatchEdgeProp("", $2, $3, $4); + } ; opt_match_edge_type_list diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index 6f139423da3..3c473813188 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -2792,6 +2792,11 @@ TEST_F(ParserTest, MatchPathPatternExpression) { auto result = parse(query); ASSERT_TRUE(result.ok()) << result.status(); } + { + std::string query = "MATCH p = (v)-[:like]->(p) WHERE (v)-[:like]->(v) RETURN p"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } } TEST_F(ParserTest, HOST) { diff --git a/tests/tck/features/match/Base.feature b/tests/tck/features/match/Base.feature index 6964d1e0696..0a7d0b375f1 100644 --- a/tests/tck/features/match/Base.feature +++ b/tests/tck/features/match/Base.feature @@ -709,3 +709,12 @@ Feature: Basic match Then the result should be, in any order: | n | | ("Boris Diaw" :player{age: 36, name: "Boris Diaw"}) | + + # Parser will treat '(v)' as match node instead label expression, so + # we can't write expression like this. + Scenario: unsupported match node expression + When executing query: + """ + MATCH (v) WHERE id(v) == 'Tim Duncan' RETURN (v) + """ + Then a SyntaxError should be raised at runtime: syntax error near `)' diff --git a/tests/tck/features/yield/yield.IntVid.feature b/tests/tck/features/yield/yield.IntVid.feature index 6fa0c5bd873..4eb90a7b876 100644 --- a/tests/tck/features/yield/yield.IntVid.feature +++ b/tests/tck/features/yield/yield.IntVid.feature @@ -516,14 +516,14 @@ Feature: Yield Sentence Scenario: deduce typecase When executing query: """ - yield split('123,456,789', ',') as l| yield [e in $-.l | (int)(e)] as c; + yield split('123,456,789', ',') as l| yield [e in $-.l | (int)e] as c; """ Then the result should be, in any order, with relax comparison: | c | | [123,456,789] | When executing query: """ - yield [e in ['123', '456', '789'] | (int)(e)] as c; + yield [e in ['123', '456', '789'] | (int)e] as c; """ Then the result should be, in any order, with relax comparison: | c | diff --git a/tests/tck/features/yield/yield.feature b/tests/tck/features/yield/yield.feature index 9eb6d8c962b..ea715a5eba1 100644 --- a/tests/tck/features/yield/yield.feature +++ b/tests/tck/features/yield/yield.feature @@ -526,14 +526,14 @@ Feature: Yield Sentence Scenario: deduce typecase When executing query: """ - yield split('123,456,789', ',') as l| yield [e in $-.l | (int)(e)] as c; + yield split('123,456,789', ',') as l| yield [e in $-.l | (int)e] as c; """ Then the result should be, in any order, with relax comparison: | c | | [123,456,789] | When executing query: """ - yield [e in ['123', '456', '789'] | (int)(e)] as c; + yield [e in ['123', '456', '789'] | (int)e] as c; """ Then the result should be, in any order, with relax comparison: | c | From bfd8718e7122d10bf4e90be03e0ccd037414e6fe Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Thu, 10 Mar 2022 11:34:00 +0800 Subject: [PATCH 6/7] Add benchmark. --- src/parser/test/ParserBenchmark.cpp | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/parser/test/ParserBenchmark.cpp b/src/parser/test/ParserBenchmark.cpp index d420f1547d9..7d3974d5458 100644 --- a/src/parser/test/ParserBenchmark.cpp +++ b/src/parser/test/ParserBenchmark.cpp @@ -15,6 +15,8 @@ auto complexQuery = "GO 2 STEPS FROM 123456789 OVER myedge " "WHERE alias.prop1 + alias.prop2 * alias.prop3 > alias.prop4 AND " "alias.prop5 == alias.prop6 YIELD 1+1+1+1+1+1+1+1 AS first, 2 AS second"; +auto matchConflictQuery = + "MATCH (a)-[r:like*2..3]->(b:team) WHERE a.prop1 = b.prop2 AND (a)-(b) RETURN a, b"; size_t SimpleQuery(size_t iters, size_t nrThreads) { constexpr size_t ops = 500000UL; @@ -66,6 +68,31 @@ size_t ComplexQuery(size_t iters, size_t nrThreads) { return iters * ops; } +size_t MatchConflictQuery(size_t iters, size_t nrThreads) { + constexpr size_t ops = 500000UL; + + auto parse = [&]() { + auto n = iters * ops; + for (auto i = 0UL; i < n; i++) { + auto qctx = std::make_unique(); + // static thread_local GQLParser parser; + GQLParser parser(qctx.get()); + auto result = parser.parse(matchConflictQuery); + folly::doNotOptimizeAway(result); + } + }; + + std::vector workers; + for (auto i = 0u; i < nrThreads; i++) { + workers.emplace_back(parse); + } + for (auto i = 0u; i < nrThreads; i++) { + workers[i].join(); + } + + return iters * ops; +} + BENCHMARK_NAMED_PARAM_MULTI(SimpleQuery, 1_thread, 1) BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(SimpleQuery, 2_thread, 2) BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(SimpleQuery, 4_thread, 4) @@ -84,6 +111,16 @@ BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(ComplexQuery, 16_thread, 16) BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(ComplexQuery, 32_thread, 32) BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(ComplexQuery, 48_thread, 48) +BENCHMARK_DRAW_LINE(); + +BENCHMARK_NAMED_PARAM_MULTI(MatchConflictQuery, 1_thread, 1) +BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(MatchConflictQuery, 2_thread, 2) +BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(MatchConflictQuery, 4_thread, 4) +BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(MatchConflictQuery, 8_thread, 8) +BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(MatchConflictQuery, 16_thread, 16) +BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(MatchConflictQuery, 32_thread, 32) +BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(MatchConflictQuery, 48_thread, 48) + int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); { From 56dc21d03f8e064aaa23c472517a731943e13458 Mon Sep 17 00:00:00 2001 From: Shylock Hg <33566796+Shylock-Hg@users.noreply.github.com> Date: Thu, 10 Mar 2022 11:38:18 +0800 Subject: [PATCH 7/7] Update benchmark info. --- src/parser/test/ParserBenchmark.cpp | 72 +++++++++++++++-------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/parser/test/ParserBenchmark.cpp b/src/parser/test/ParserBenchmark.cpp index 7d3974d5458..58def88fd14 100644 --- a/src/parser/test/ParserBenchmark.cpp +++ b/src/parser/test/ParserBenchmark.cpp @@ -140,44 +140,46 @@ int main(int argc, char **argv) { return 0; } -/* Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz, 20core 40thread - - Non-Thread-Local +/* +Architecture: x86_64 +CPU op-mode(s): 32-bit, 64-bit +Byte Order: Little Endian +Address sizes: 46 bits physical, 57 bits virtual +CPU(s): 128 +On-line CPU(s) list: 0-127 +Thread(s) per core: 2 +Core(s) per socket: 32 +Socket(s): 2 +NUMA node(s): 2 +Vendor ID: GenuineIntel +CPU family: 6 +Model: 106 +Model name: Intel(R) Xeon(R) Platinum 8352Y CPU @ 2.20GHz ============================================================================ -src/parser/test/ParserBenchmark.cpp relative time/iter iters/s +/home/shylock.huang/nebula-tmp/src/parser/test/ParserBenchmark.cpprelative time/iter iters/s ============================================================================ -SimpleQuery(1_thread) 892.36ns 1.12M -SimpleQuery(2_thread) 67.21% 1.33us 753.21K -SimpleQuery(4_thread) 41.68% 2.14us 467.11K -SimpleQuery(8_thread) 19.62% 4.55us 219.92K -SimpleQuery(16_thread) 9.62% 9.28us 107.76K -SimpleQuery(32_thread) 5.32% 16.76us 59.66K -SimpleQuery(48_thread) 3.98% 22.43us 44.58K +SimpleQuery(1_thread) 1.70us 587.21K +SimpleQuery(2_thread) 96.72% 1.76us 567.92K +SimpleQuery(4_thread) 97.35% 1.75us 571.67K +SimpleQuery(8_thread) 96.84% 1.76us 568.66K +SimpleQuery(16_thread) 95.77% 1.78us 562.36K +SimpleQuery(32_thread) 53.77% 3.17us 315.74K +SimpleQuery(48_thread) 49.68% 3.43us 291.73K ---------------------------------------------------------------------------- -ComplexQuery(1_thread) 6.40us 156.16K -ComplexQuery(2_thread) 100.48% 6.37us 156.91K -ComplexQuery(4_thread) 92.96% 6.89us 145.16K -ComplexQuery(8_thread) 82.83% 7.73us 129.36K -ComplexQuery(16_thread) 61.58% 10.40us 96.16K -ComplexQuery(32_thread) 35.98% 17.80us 56.19K -ComplexQuery(48_thread) 26.24% 24.41us 40.97K -============================================================================ - Thread-Local(Reentrant) -============================================================================ -SimpleQuery(1_thread) 496.38ns 2.01M -SimpleQuery(2_thread) 91.86% 540.35ns 1.85M -SimpleQuery(4_thread) 89.51% 554.53ns 1.80M -SimpleQuery(8_thread) 89.86% 552.42ns 1.81M -SimpleQuery(16_thread) 58.34% 850.83ns 1.18M -SimpleQuery(32_thread) 56.01% 886.22ns 1.13M -SimpleQuery(48_thread) 39.20% 1.27us 789.64K +ComplexQuery(1_thread) 9.94us 100.57K +ComplexQuery(2_thread) 98.73% 10.07us 99.30K +ComplexQuery(4_thread) 101.62% 9.78us 102.21K +ComplexQuery(8_thread) 90.47% 10.99us 90.99K +ComplexQuery(16_thread) 97.32% 10.22us 97.87K +ComplexQuery(32_thread) 69.31% 14.34us 69.71K +ComplexQuery(48_thread) 61.30% 16.22us 61.66K ---------------------------------------------------------------------------- -ComplexQuery(1_thread) 5.15us 194.04K -ComplexQuery(2_thread) 93.48% 5.51us 181.38K -ComplexQuery(4_thread) 94.62% 5.45us 183.59K -ComplexQuery(8_thread) 92.52% 5.57us 179.53K -ComplexQuery(16_thread) 79.93% 6.45us 155.09K -ComplexQuery(32_thread) 60.09% 8.58us 116.60K -ComplexQuery(48_thread) 44.15% 11.67us 85.67K +MatchConflictQuery(1_thread) 3.88us 257.41K +MatchConflictQuery(2_thread) 99.74% 3.90us 256.73K +MatchConflictQuery(4_thread) 96.16% 4.04us 247.52K +MatchConflictQuery(8_thread) 79.93% 4.86us 205.74K +MatchConflictQuery(16_thread) 79.57% 4.88us 204.81K +MatchConflictQuery(32_thread) 56.12% 6.92us 144.47K +MatchConflictQuery(48_thread) 50.41% 7.71us 129.75K ============================================================================ */