diff --git a/src/graph/validator/YieldValidator.cpp b/src/graph/validator/YieldValidator.cpp index 6c388449cba..688d546c1c7 100644 --- a/src/graph/validator/YieldValidator.cpp +++ b/src/graph/validator/YieldValidator.cpp @@ -23,8 +23,9 @@ Status YieldValidator::validateImpl() { if (qctx_->vctx()->spaceChosen()) { space_ = vctx_->whichSpace(); } - auto yield = static_cast(sentence_); + isDistinct_ = yield->yield()->isDistinct(); + if (yield->yield()->yields()->hasAgg()) { NG_RETURN_IF_ERROR(makeImplicitGroupByValidator()); } @@ -45,16 +46,18 @@ Status YieldValidator::validateImpl() { return Status::SemanticError("Not support both input and variable."); } - if (!exprProps_.varProps().empty() && exprProps_.varProps().size() > 1) { - return Status::SemanticError("Only one variable allowed to use."); - } + if (yield->joinClause() == nullptr) { + if (!exprProps_.varProps().empty() && exprProps_.varProps().size() > 1) { + return Status::SemanticError("Only one variable allowed to use."); + } - if (!exprProps_.varProps().empty() && !userDefinedVarNameList_.empty()) { - // TODO: Support Multiple userDefinedVars - if (userDefinedVarNameList_.size() != 1) { - return Status::SemanticError("Multiple user defined vars not supported yet."); + if (!exprProps_.varProps().empty() && !userDefinedVarNameList_.empty()) { + // TODO: Support Multiple userDefinedVars + if (userDefinedVarNameList_.size() != 1) { + return Status::SemanticError("Multiple user defined vars not supported yet."); + } + userDefinedVarName_ = *userDefinedVarNameList_.begin(); } - userDefinedVarName_ = *userDefinedVarNameList_.begin(); } return Status::OK(); @@ -177,42 +180,83 @@ Status YieldValidator::validateJoin(const JoinClause *join) { if (join == nullptr) { return Status::OK(); } + + if (join->joinMode() != JoinMode::kInnerJoin) { + return Status::SemanticError("only support inner join."); + } + auto *leftVarExpr = join->leftVarExpr(); auto *rightVarExpr = join->rightVarExpr(); DCHECK_EQ(leftVarExpr->kind(), Expression::Kind::kVar); DCHECK_EQ(rightVarExpr->kind(), Expression::Kind::kVar); - auto leftVar = static_cast(leftVarExpr)->var(); - auto rightVar = static_cast(rightVarExpr)->var(); - - auto *leftConditionExpr = join->leftConditionExpr(); - auto *rightConditionExpr = join->rightConditionExpr(); - DCHECK_EQ(leftConditionExpr->kind(), Expression::Kind::kVarProperty); - DCHECK_EQ(rightConditionExpr->kind(), Expression::Kind::kVarProperty); - auto &leftConditionVar = static_cast(leftConditionExpr)->sym(); - auto &rightConditionVar = static_cast(rightConditionExpr)->sym(); + leftVar_ = static_cast(leftVarExpr)->var(); + rightVar_ = static_cast(rightVarExpr)->var(); + + leftConditionExpr_ = join->leftConditionExpr(); + rightConditionExpr_ = join->rightConditionExpr(); + DCHECK_EQ(leftConditionExpr_->kind(), Expression::Kind::kVarProperty); + DCHECK_EQ(rightConditionExpr_->kind(), Expression::Kind::kVarProperty); + auto &leftConditionVar = static_cast(leftConditionExpr_)->sym(); + auto &rightConditionVar = static_cast(rightConditionExpr_)->sym(); + + if (leftVar_ == rightVar_) { + return Status::SemanticError("do not support self-join."); + } - if (leftVar != leftConditionVar) { + if (leftVar_ != leftConditionVar) { return Status::SemanticError("`%s' should be consistent with join condition variable `%s'.", - leftVar.c_str(), + leftVar_.c_str(), leftConditionVar.c_str()); } - if (rightVar != rightConditionVar) { + if (rightVar_ != rightConditionVar) { return Status::SemanticError("`%s' should be consistent with join condition variable `%s'.", - rightVar.c_str(), + rightVar_.c_str(), rightConditionVar.c_str()); } - auto typeStatus = deduceExprType(leftConditionExpr); + auto typeStatus = deduceExprType(leftConditionExpr_); NG_RETURN_IF_ERROR(typeStatus); - typeStatus = deduceExprType(rightConditionExpr); + typeStatus = deduceExprType(rightConditionExpr_); NG_RETURN_IF_ERROR(typeStatus); return Status::OK(); } +Status YieldValidator::buildJoinPlan() { + auto *varPtr = qctx_->symTable()->getVar(leftVar_); + DCHECK(varPtr != nullptr); + std::vector colNames = varPtr->colNames; + + varPtr = qctx_->symTable()->getVar(rightVar_); + DCHECK(varPtr != nullptr); + colNames.insert(colNames.end(), varPtr->colNames.begin(), varPtr->colNames.end()); + + auto *join = InnerJoin::make(qctx_, + nullptr, + {leftVar_, ExecutionContext::kLatestVersion}, + {rightVar_, ExecutionContext::kLatestVersion}, + {leftConditionExpr_}, + {rightConditionExpr_}); + join->setColNames(std::move(colNames)); + + auto *project = Project::make(qctx_, join, columns_); + project->setColNames(getOutColNames()); + + if (isDistinct_) { + root_ = Dedup::make(qctx_, project); + } else { + root_ = project; + } + tail_ = join; + return Status::OK(); +} + // Generate plan according to input, implicit group by and yield columns. Status YieldValidator::toPlan() { auto yield = static_cast(sentence_); + if (yield->joinClause()) { + return buildJoinPlan(); + } std::string inputVar; std::vector colNames(inputs_.size()); @@ -271,7 +315,7 @@ Status YieldValidator::toPlan() { } } - if (yield->yield()->isDistinct()) { + if (isDistinct_) { root_ = Dedup::make(qctx_, dedupDep); } else { root_ = dedupDep; diff --git a/src/graph/validator/YieldValidator.h b/src/graph/validator/YieldValidator.h index 8b3133bc58d..234cc3acde9 100644 --- a/src/graph/validator/YieldValidator.h +++ b/src/graph/validator/YieldValidator.h @@ -39,15 +39,21 @@ class YieldValidator final : public Validator { Status makeOutputColumn(YieldColumn *column); Status makeImplicitGroupByValidator(); Status validateImplicitGroupBy(); - void genConstantExprValues(); + Status buildJoinPlan(); private: + bool isDistinct_{false}; YieldColumns *columns_{nullptr}; std::string constantExprVar_; std::string userDefinedVarName_; Expression *filterCondition_{nullptr}; // validate for agg std::unique_ptr groupByValidator_{nullptr}; + + std::string leftVar_; + std::string rightVar_; + Expression *leftConditionExpr_{nullptr}; + Expression *rightConditionExpr_{nullptr}; }; } // namespace graph diff --git a/src/parser/Clauses.h b/src/parser/Clauses.h index c959b1fff70..5b5291f11b0 100644 --- a/src/parser/Clauses.h +++ b/src/parser/Clauses.h @@ -525,6 +525,10 @@ class JoinClause final { return rightConditionExpr_; } + JoinMode joinMode() const { + return joinMode_; + } + std::string toString() const; private: diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 17171d087e0..a456ea3e618 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -19,7 +19,6 @@ #include #include "parser/ExplainSentence.h" #include "parser/SequentialSentences.h" -#include "parser/Clauses.h" #include "interface/gen-cpp2/meta_types.h" #include "common/expression/AttributeExpression.h" #include "common/expression/LabelAttributeExpression.h"