diff --git a/src/optimizer/OptimizerUtils.cpp b/src/optimizer/OptimizerUtils.cpp index 7f261c1604d943679746ac71607c8787a841f59b..c5592026219dad1b9f35cbca9ca248f304edd75a 100644 --- a/src/optimizer/OptimizerUtils.cpp +++ b/src/optimizer/OptimizerUtils.cpp @@ -26,7 +26,7 @@ Value OptimizerUtils::boundValue(const meta::cpp2::ColumnDef& col, return boundValueWithMin(col, v); } } - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } Value OptimizerUtils::boundValueWithGT(const meta::cpp2::ColumnDef& col, const Value& v) { @@ -59,7 +59,7 @@ Value OptimizerUtils::boundValueWithGT(const meta::cpp2::ColumnDef& col, const V case Value::Type::STRING : { if (!col.type.__isset.type_length || col.get_type().get_type_length() == nullptr) { - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } std::vector<unsigned char> bytes(v.getStr().begin(), v.getStr().end()); bytes.resize(*col.get_type().get_type_length()); @@ -172,11 +172,11 @@ Value OptimizerUtils::boundValueWithGT(const meta::cpp2::ColumnDef& col, const V case Value::Type::PATH: { DLOG(FATAL) << "Not supported value type " << type << "for index."; - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } } DLOG(FATAL) << "Unknown value type " << static_cast<int>(type); - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } Value OptimizerUtils::boundValueWithLT(const meta::cpp2::ColumnDef& col, const Value& v) { @@ -206,7 +206,7 @@ Value OptimizerUtils::boundValueWithLT(const meta::cpp2::ColumnDef& col, const V } case Value::Type::STRING : { if (!col.type.__isset.type_length || col.get_type().get_type_length() == nullptr) { - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } std::vector<unsigned char> bytes(v.getStr().begin(), v.getStr().end()); bytes.resize(*col.get_type().get_type_length()); @@ -321,11 +321,11 @@ Value OptimizerUtils::boundValueWithLT(const meta::cpp2::ColumnDef& col, const V case Value::Type::PATH: { DLOG(FATAL) << "Not supported value type " << type << "for index."; - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } } DLOG(FATAL) << "Unknown value type " << static_cast<int>(type); - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } Value OptimizerUtils::boundValueWithMax(const meta::cpp2::ColumnDef& col, const Value& v) { @@ -343,7 +343,7 @@ Value OptimizerUtils::boundValueWithMax(const meta::cpp2::ColumnDef& col, const case Value::Type::STRING : { if (!col.type.__isset.type_length || col.get_type().get_type_length() == nullptr) { - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } return Value(std::string(*col.get_type().get_type_length(), '\377')); } @@ -384,11 +384,11 @@ Value OptimizerUtils::boundValueWithMax(const meta::cpp2::ColumnDef& col, const case Value::Type::PATH: { DLOG(FATAL) << "Not supported value type " << type << "for index."; - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } } DLOG(FATAL) << "Unknown value type " << static_cast<int>(type); - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } Value OptimizerUtils::boundValueWithMin(const meta::cpp2::ColumnDef& col, const Value& v) { @@ -406,7 +406,7 @@ Value OptimizerUtils::boundValueWithMin(const meta::cpp2::ColumnDef& col, const case Value::Type::STRING : { if (!col.type.__isset.type_length || col.get_type().get_type_length() == nullptr) { - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } return Value(std::string(*col.get_type().get_type_length(), '\0')); } @@ -430,11 +430,55 @@ Value OptimizerUtils::boundValueWithMin(const meta::cpp2::ColumnDef& col, const case Value::Type::PATH: { DLOG(FATAL) << "Not supported value type " << type << "for index."; - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; } } DLOG(FATAL) << "Unknown value type " << static_cast<int>(type); - return Value(NullType::BAD_TYPE); + return Value::kNullBadType; +} + +Value OptimizerUtils::normalizeValue(const meta::cpp2::ColumnDef& col, const Value& v) { + auto type = SchemaUtil::propTypeToValueType(col.get_type().get_type()); + switch (type) { + case Value::Type::INT: + case Value::Type::FLOAT: + case Value::Type::BOOL: + case Value::Type::DATE: + case Value::Type::TIME: + case Value::Type::DATETIME: { + return v; + } + case Value::Type::STRING : { + if (!col.type.__isset.type_length || + col.get_type().get_type_length() == nullptr) { + return Value::kNullBadType; + } + auto len = static_cast<size_t>(*col.get_type().get_type_length()); + if (v.getStr().size() > len) { + return Value(v.getStr().substr(0, len)); + } else { + std::string s; + s.reserve(len); + s.append(v.getStr()).append(len - v.getStr().size(), '\0'); + return Value(std::move(s)); + } + } + case Value::Type::__EMPTY__: + case Value::Type::NULLVALUE: + case Value::Type::VERTEX: + case Value::Type::EDGE: + case Value::Type::LIST: + case Value::Type::SET: + case Value::Type::MAP: + case Value::Type::DATASET: + case Value::Type::PATH: { + DLOG(FATAL) << "Not supported value type " << type + << "for index."; + return Value::kNullBadType; + } + } + DLOG(FATAL) << "Unknown value type " << static_cast<int>(type); + return Value::kNullBadType;; } } // namespace graph diff --git a/src/optimizer/OptimizerUtils.h b/src/optimizer/OptimizerUtils.h index 60f526b51c69831431f2aa50f678fac0cfc7fa3c..8870a436419c2d9e9bc4bb4ee01c08d2c1621d55 100644 --- a/src/optimizer/OptimizerUtils.h +++ b/src/optimizer/OptimizerUtils.h @@ -36,6 +36,8 @@ public: static Value boundValueWithMax(const meta::cpp2::ColumnDef& col, const Value& v); static Value boundValueWithMin(const meta::cpp2::ColumnDef& col, const Value& v); + + static Value normalizeValue(const meta::cpp2::ColumnDef& col, const Value& v); }; } // namespace graph diff --git a/src/optimizer/rule/IndexScanRule.cpp b/src/optimizer/rule/IndexScanRule.cpp index cf250255dcc6d48e38489c8d8534b96afa54dc10..9a50f3d55186bde68e53e533a0aee9a49ea99a04 100644 --- a/src/optimizer/rule/IndexScanRule.cpp +++ b/src/optimizer/rule/IndexScanRule.cpp @@ -76,8 +76,9 @@ Status IndexScanRule::createIQCWithLogicAnd(IndexQueryCtx &iqctx, if (index == nullptr) { return Status::IndexNotFound("No valid index found"); } - - return appendIQCtx(index, items, iqctx); + auto in = static_cast<const IndexScan *>(groupNode->node()); + const auto& filter = in->queryContext()->begin()->get_filter(); + return appendIQCtx(index, items, iqctx, filter); } Status IndexScanRule::createIQCWithLogicOR(IndexQueryCtx &iqctx, @@ -95,9 +96,19 @@ Status IndexScanRule::createIQCWithLogicOR(IndexQueryCtx &iqctx, return Status::OK(); } +size_t IndexScanRule::hintCount(const FilterItems& items) const noexcept { + std::unordered_set<std::string> hintCols; + for (const auto& i : items.items) { + hintCols.emplace(i.col_); + } + return hintCols.size(); +} + Status IndexScanRule::appendIQCtx(const IndexItem& index, const FilterItems& items, - IndexQueryCtx &iqctx) const { + IndexQueryCtx &iqctx, + const std::string& filter) const { + auto hc = hintCount(items); auto fields = index->get_fields(); IndexQueryContext ctx; decltype(ctx.column_hints) hints; @@ -112,18 +123,26 @@ Status IndexScanRule::appendIQCtx(const IndexItem& index, found = true; } if (!found) break; - // TODO (sky) : rewrite filter expr. NE expr should be add filter expr . auto it = std::find_if(filterItems.items.begin(), filterItems.items.end(), [](const auto &ite) { return ite.relOP_ == RelationalExpression::Kind::kRelNE; }); if (it != filterItems.items.end()) { + // TODO (sky) : rewrite filter expr. NE expr should be add filter expr . + ctx.set_filter(filter); break; } NG_RETURN_IF_ERROR(appendColHint(hints, filterItems, field)); + hc--; + if (filterItems.items.begin()->relOP_ != RelationalExpression::Kind::kRelEQ) { + break; + } } ctx.set_index_id(index->get_index_id()); - // TODO (sky) : rewrite expr and set filter + if (hc > 0) { + // TODO (sky) : rewrite expr and set filter + ctx.set_filter(filter); + } ctx.set_column_hints(std::move(hints)); iqctx->emplace_back(std::move(ctx)); return Status::OK(); @@ -131,7 +150,7 @@ Status IndexScanRule::appendIQCtx(const IndexItem& index, #define CHECK_BOUND_VALUE(v, name) \ do { \ - if (v == Value(NullType::BAD_TYPE)) { \ + if (v == Value::kNullBadType) { \ LOG(ERROR) << "Get bound value error. field : " << name; \ return Status::Error("Get bound value error. field : %s", name.c_str()); \ } \ @@ -151,7 +170,7 @@ Status IndexScanRule::appendColHint(std::vector<IndexColumnHint>& hints, return Status::SemanticError(); } isRangeScan = false; - begin = item.value_; + begin = OptimizerUtils::normalizeValue(col, item.value_); break; } NG_RETURN_IF_ERROR(boundValue(item, col, begin, end)); diff --git a/src/optimizer/rule/IndexScanRule.h b/src/optimizer/rule/IndexScanRule.h index 8ba09e34ac5521719a5cac76fadcf3140b539934..4e0f0a5c24449e5a8406e0b65eee4e7f4d86f12d 100644 --- a/src/optimizer/rule/IndexScanRule.h +++ b/src/optimizer/rule/IndexScanRule.h @@ -119,7 +119,8 @@ private: Status appendIQCtx(const IndexItem& index, const FilterItems& items, - IndexQueryCtx &iqctx) const; + IndexQueryCtx &iqctx, + const std::string& filter = "") const; Status appendColHint(std::vector<IndexColumnHint>& hitns, const FilterItems& items, @@ -129,6 +130,8 @@ private: const meta::cpp2::ColumnDef& col, Value& begin, Value& end) const; + size_t hintCount(const FilterItems& items) const noexcept; + bool isEdge(const OptGroupNode *groupNode) const; int32_t schemaId(const OptGroupNode *groupNode) const; diff --git a/src/optimizer/test/IndexScanRuleTest.cpp b/src/optimizer/test/IndexScanRuleTest.cpp index 947340a18aaaab64b2aa47af9e0d8603d9710126..f215e76b3ab8b01f3a35f56b6d67c26da402623c 100644 --- a/src/optimizer/test/IndexScanRuleTest.cpp +++ b/src/optimizer/test/IndexScanRuleTest.cpp @@ -144,7 +144,7 @@ TEST(IndexScanRuleTest, IQCtxTest) { ASSERT_TRUE(ret.ok()); ASSERT_EQ(1, iqctx->size()); - ASSERT_EQ(5, (iqctx.get()->begin())->get_column_hints().size()); + ASSERT_EQ(1, (iqctx.get()->begin())->get_column_hints().size()); ASSERT_EQ(1, (iqctx.get()->begin())->get_index_id()); ASSERT_EQ("", (iqctx.get()->begin())->get_filter()); const auto& colHints = (iqctx.get()->begin())->get_column_hints(); @@ -155,43 +155,16 @@ TEST(IndexScanRuleTest, IQCtxTest) { ASSERT_EQ(Value(2L), hint.get_begin_value()); ASSERT_EQ(Value(std::numeric_limits<int64_t>::max()), hint.get_end_value()); } - { - auto hint = colHints[1]; - ASSERT_EQ("col1", hint.get_column_name()); - ASSERT_EQ(storage::cpp2::ScanType::RANGE, hint.get_scan_type()); - ASSERT_EQ(Value(0L), hint.get_begin_value()); - ASSERT_EQ(Value(3L), hint.get_end_value()); - } - { - auto hint = colHints[2]; - ASSERT_EQ("col2", hint.get_column_name()); - ASSERT_EQ(storage::cpp2::ScanType::RANGE, hint.get_scan_type()); - ASSERT_EQ(Value(4L), hint.get_begin_value()); - ASSERT_EQ(Value(std::numeric_limits<int64_t>::max()), hint.get_end_value()); - } - { - auto hint = colHints[3]; - ASSERT_EQ("col3", hint.get_column_name()); - ASSERT_EQ(storage::cpp2::ScanType::RANGE, hint.get_scan_type()); - ASSERT_EQ(Value(std::numeric_limits<int64_t>::min()), hint.get_begin_value()); - ASSERT_EQ(Value(4L), hint.get_end_value()); - } - { - auto hint = colHints[4]; - ASSERT_EQ("col4", hint.get_column_name()); - ASSERT_EQ(storage::cpp2::ScanType::PREFIX, hint.get_scan_type()); - ASSERT_EQ(Value(4L), hint.get_begin_value()); - } } - // setup FilterItems col0 > 1 and col1 <= 2 and col1 > -1 and col2 != 3 + // setup FilterItems col0 == 1 and col1 <= 2 and col1 > -1 and col2 != 3 // and col3 < 4 // only expect col0 and col1 exits in column hints. // col2 and col3 should be filter in storage layer. { items.items.clear(); iqctx.get()->clear(); - items.addItem("col0", RelationalExpression::Kind::kRelGT, Value(1L)); + items.addItem("col0", RelationalExpression::Kind::kRelEQ, Value(1L)); items.addItem("col1", RelationalExpression::Kind::kRelLE, Value(2L)); items.addItem("col1", RelationalExpression::Kind::kRelGT, Value(-1L)); items.addItem("col2", RelationalExpression::Kind::kRelNE, Value(3L)); @@ -208,9 +181,8 @@ TEST(IndexScanRuleTest, IQCtxTest) { { auto hint = colHints[0]; ASSERT_EQ("col0", hint.get_column_name()); - ASSERT_EQ(storage::cpp2::ScanType::RANGE, hint.get_scan_type()); - ASSERT_EQ(Value(2L), hint.get_begin_value()); - ASSERT_EQ(Value(std::numeric_limits<int64_t>::max()), hint.get_end_value()); + ASSERT_EQ(storage::cpp2::ScanType::PREFIX, hint.get_scan_type()); + ASSERT_EQ(Value(1L), hint.get_begin_value()); } { auto hint = colHints[1]; @@ -220,6 +192,53 @@ TEST(IndexScanRuleTest, IQCtxTest) { ASSERT_EQ(Value(3L), hint.get_end_value()); } } + // setup FilterItems col0 == 1 and col1 == 2 and col2 == -1 and col3 > 3 + // and col4 < 4 + // only expect col0, col1, col2 and col3 exits in column hints. + // col4 should be filter in storage layer. + { + items.items.clear(); + iqctx.get()->clear(); + items.addItem("col0", RelationalExpression::Kind::kRelEQ, Value(1L)); + items.addItem("col1", RelationalExpression::Kind::kRelEQ, Value(2L)); + items.addItem("col2", RelationalExpression::Kind::kRelEQ, Value(-1L)); + items.addItem("col3", RelationalExpression::Kind::kRelGT, Value(3L)); + items.addItem("col4", RelationalExpression::Kind::kRelLT, Value(4L)); + + auto ret = instance->appendIQCtx(index, items, iqctx, "col4 < 4"); + ASSERT_TRUE(ret.ok()); + + ASSERT_EQ(1, iqctx->size()); + ASSERT_EQ(4, (iqctx.get()->begin())->get_column_hints().size()); + ASSERT_EQ(1, (iqctx.get()->begin())->get_index_id()); + ASSERT_EQ("col4 < 4", (iqctx.get()->begin())->get_filter()); + const auto& colHints = (iqctx.get()->begin())->get_column_hints(); + { + auto hint = colHints[0]; + ASSERT_EQ("col0", hint.get_column_name()); + ASSERT_EQ(storage::cpp2::ScanType::PREFIX, hint.get_scan_type()); + ASSERT_EQ(Value(1L), hint.get_begin_value()); + } + { + auto hint = colHints[1]; + ASSERT_EQ("col1", hint.get_column_name()); + ASSERT_EQ(storage::cpp2::ScanType::PREFIX, hint.get_scan_type()); + ASSERT_EQ(Value(2L), hint.get_begin_value()); + } + { + auto hint = colHints[2]; + ASSERT_EQ("col2", hint.get_column_name()); + ASSERT_EQ(storage::cpp2::ScanType::PREFIX, hint.get_scan_type()); + ASSERT_EQ(Value(-1L), hint.get_begin_value()); + } + { + auto hint = colHints[3]; + ASSERT_EQ("col3", hint.get_column_name()); + ASSERT_EQ(storage::cpp2::ScanType::RANGE, hint.get_scan_type()); + ASSERT_EQ(Value(4L), hint.get_begin_value()); + ASSERT_EQ(Value(std::numeric_limits<int64_t>::max()), hint.get_end_value()); + } + } } } diff --git a/src/parser/MaintainSentences.cpp b/src/parser/MaintainSentences.cpp index a690a4733e97e72bb0bc916824e0b95cd4a7cefd..30d1353c3baf7e2b2a2d4e0dd6c1601e21f6fd79 100644 --- a/src/parser/MaintainSentences.cpp +++ b/src/parser/MaintainSentences.cpp @@ -238,9 +238,15 @@ std::string CreateTagIndexSentence::toString() const { buf += " ON "; buf += *tagName_; buf += " ("; - std::string columns; - folly::join(", ", this->columns(), columns); - buf += columns; + std::vector<std::string> fieldDefs; + for (const auto& field : this->fields()) { + std::string f = field.get_name(); + if (field.__isset.type_length) f + "(" +field.get_type_length() + ")"; + fieldDefs.emplace_back(std::move(f)); + } + std::string fields; + folly::join(", ", fieldDefs, fields); + buf += fields; buf += ")"; return buf; } @@ -254,9 +260,15 @@ std::string CreateEdgeIndexSentence::toString() const { buf += " ON "; buf += *edgeName_; buf += " ("; - std::string columns; - folly::join(", ", this->columns(), columns); - buf += columns; + std::vector<std::string> fieldDefs; + for (const auto& field : this->fields()) { + std::string f = field.get_name(); + if (field.__isset.type_length) f + "(" +field.get_type_length() + ")"; + fieldDefs.emplace_back(std::move(f)); + } + std::string fields; + folly::join(", ", fieldDefs, fields); + buf += fields; buf += ")"; return buf; } diff --git a/src/parser/MaintainSentences.h b/src/parser/MaintainSentences.h index 7667daa04f171b82d024849f2a7a0ae738083cf3..6597f602f87b21cb30d751ba997d106aa839015d 100644 --- a/src/parser/MaintainSentences.h +++ b/src/parser/MaintainSentences.h @@ -483,16 +483,37 @@ private: }; +class IndexFieldList final { +public: + IndexFieldList() = default; + + void addField(std::unique_ptr<meta::cpp2::IndexFieldDef> field) { + fields_.emplace_back(std::move(field)); + } + + std::vector<meta::cpp2::IndexFieldDef*> fields() const { + std::vector<meta::cpp2::IndexFieldDef*> result; + result.resize(fields_.size()); + auto get = [] (auto &ptr) { return ptr.get(); }; + std::transform(fields_.begin(), fields_.end(), result.begin(), get); + return result; + } + +private: + std::vector<std::unique_ptr<meta::cpp2::IndexFieldDef>> fields_; +}; + + class CreateTagIndexSentence final : public CreateSentence { public: CreateTagIndexSentence(std::string *indexName, std::string *tagName, - ColumnNameList *columns, + IndexFieldList *fields, bool ifNotExists) : CreateSentence(ifNotExists) { indexName_.reset(indexName); tagName_.reset(tagName); - columns_.reset(columns); + fields_.reset(fields); kind_ = Kind::kCreateTagIndex; } @@ -506,19 +527,19 @@ public: return tagName_.get(); } - std::vector<std::string> columns() const { - std::vector<std::string> result; - auto columnNames = columns_->columnNames(); - result.resize(columnNames.size()); + std::vector<meta::cpp2::IndexFieldDef> fields() const { + std::vector<meta::cpp2::IndexFieldDef> result; + auto fields = fields_->fields(); + result.resize(fields.size()); auto get = [] (auto ptr) { return *ptr; }; - std::transform(columnNames.begin(), columnNames.end(), result.begin(), get); + std::transform(fields.begin(), fields.end(), result.begin(), get); return result; } private: std::unique_ptr<std::string> indexName_; std::unique_ptr<std::string> tagName_; - std::unique_ptr<ColumnNameList> columns_; + std::unique_ptr<IndexFieldList> fields_; }; @@ -526,12 +547,12 @@ class CreateEdgeIndexSentence final : public CreateSentence { public: CreateEdgeIndexSentence(std::string *indexName, std::string *edgeName, - ColumnNameList *columns, + IndexFieldList *fields, bool ifNotExists) : CreateSentence(ifNotExists) { indexName_.reset(indexName); edgeName_.reset(edgeName); - columns_.reset(columns); + fields_.reset(fields); kind_ = Kind::kCreateEdgeIndex; } @@ -545,19 +566,19 @@ public: return edgeName_.get(); } - std::vector<std::string> columns() const { - std::vector<std::string> result; - auto columnNames = columns_->columnNames(); - result.resize(columnNames.size()); + std::vector<meta::cpp2::IndexFieldDef> fields() const { + std::vector<meta::cpp2::IndexFieldDef> result; + auto fields = fields_->fields(); + result.resize(fields.size()); auto get = [] (auto ptr) { return *ptr; }; - std::transform(columnNames.begin(), columnNames.end(), result.begin(), get); + std::transform(fields.begin(), fields.end(), result.begin(), get); return result; } private: std::unique_ptr<std::string> indexName_; std::unique_ptr<std::string> edgeName_; - std::unique_ptr<ColumnNameList> columns_; + std::unique_ptr<IndexFieldList> fields_; }; diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 7ad5b791930e4f41947874a6b0c9eb520ec25e78..d7969cf1e027d5c20c7d564f89bf18fd4feb599d 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -115,6 +115,8 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL; ReadingClause *reading_clause; MatchClauseList *match_clause_list; MatchStepRange *match_step_range; + nebula::meta::cpp2::IndexFieldDef *index_field; + nebula::IndexFieldList *index_field_list; } /* destructors */ @@ -261,6 +263,9 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL; %type <role_type_clause> role_type_clause %type <acl_item_clause> acl_item_clause +%type <index_field> index_field +%type <index_field_list> index_field_list + %type <sentence> maintain_sentence %type <sentence> create_space_sentence describe_space_sentence drop_space_sentence %type <sentence> create_tag_sentence create_edge_sentence @@ -1638,14 +1643,46 @@ drop_edge_sentence } ; +index_field + : name_label { + $$ = new meta::cpp2::IndexFieldDef(); + $$->set_name($1->c_str()); + delete $1; + } + | name_label L_PAREN INTEGER R_PAREN { + if ($3 > std::numeric_limits<int16_t>::max()) { + throw nebula::GraphParser::syntax_error(@3, "Out of range:"); + } + $$ = new meta::cpp2::IndexFieldDef(); + $$->set_name($1->c_str()); + $$->set_type_length($3); + delete $1; + } + ; + +index_field_list + : index_field { + $$ = new IndexFieldList(); + std::unique_ptr<meta::cpp2::IndexFieldDef> field; + field.reset($1); + $$->addField(std::move(field)); + } + | index_field_list COMMA index_field { + $$ = $1; + std::unique_ptr<meta::cpp2::IndexFieldDef> field; + field.reset($3); + $$->addField(std::move(field)); + } + ; + create_tag_index_sentence - : KW_CREATE KW_TAG KW_INDEX opt_if_not_exists name_label KW_ON name_label L_PAREN column_name_list R_PAREN { + : KW_CREATE KW_TAG KW_INDEX opt_if_not_exists name_label KW_ON name_label L_PAREN index_field_list R_PAREN { $$ = new CreateTagIndexSentence($5, $7, $9, $4); } ; create_edge_index_sentence - : KW_CREATE KW_EDGE KW_INDEX opt_if_not_exists name_label KW_ON name_label L_PAREN column_name_list R_PAREN { + : KW_CREATE KW_EDGE KW_INDEX opt_if_not_exists name_label KW_ON name_label L_PAREN index_field_list R_PAREN { $$ = new CreateEdgeIndexSentence($5, $7, $9, $4); } ; diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index 6d1a60034370861c12da7e0a184432304ad709d3..e8e3e72b1d889dbdae18bccdb52739ad28aa2769 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -504,6 +504,42 @@ TEST(Parser, IndexOperation) { auto result = parser.parse(query); ASSERT_TRUE(result.ok()) << result.status(); } + { + GQLParser parser; + std::string query = "CREATE EDGE INDEX IF NOT EXISTS std_index ON t1(c1(10), c2(20))"; + auto result = parser.parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + GQLParser parser; + std::string query = "CREATE EDGE INDEX IF NOT EXISTS std_index ON t1(c1, c2(20))"; + auto result = parser.parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + GQLParser parser; + std::string query = "CREATE EDGE INDEX IF NOT EXISTS std_index ON t1(c1(10), c2)"; + auto result = parser.parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + GQLParser parser; + std::string query = "CREATE TAG INDEX IF NOT EXISTS std_index ON t1(c1(10), c2(20))"; + auto result = parser.parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + GQLParser parser; + std::string query = "CREATE TAG INDEX IF NOT EXISTS std_index ON t1(c1, c2(20))"; + auto result = parser.parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + GQLParser parser; + std::string query = "CREATE TAG INDEX IF NOT EXISTS std_index ON t1(c1(10), c2)"; + auto result = parser.parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } { GQLParser parser; std::string query = "DROP TAG INDEX name_index"; diff --git a/src/planner/Maintain.cpp b/src/planner/Maintain.cpp index 69bbc7399c7356c37000816efc36425d28ab6244..65a968ddbc368a6c055b03c5f1ed00940a8ce2e5 100644 --- a/src/planner/Maintain.cpp +++ b/src/planner/Maintain.cpp @@ -48,8 +48,12 @@ std::unique_ptr<cpp2::PlanNodeDescription> CreateIndexNode::explain() const { auto desc = SingleInputNode::explain(); addDescription("schemaName", schemaName_, desc.get()); addDescription("indexName", indexName_, desc.get()); - addDescription("fields", folly::toJson(util::toJson(fields_)), desc.get()); - addDescription("ifNotExists", util::toJson(ifNotExists_), desc.get()); + std::vector<std::string> fields; + for (const auto& field : fields_) { + fields.emplace_back(field.get_name()); + } + addDescription("fields", folly::toJson(util::toJson(fields)), desc.get()); + addDescription("ifNotExists", folly::to<std::string>(ifNotExists_), desc.get()); return desc; } diff --git a/src/planner/Maintain.h b/src/planner/Maintain.h index 5c87532cb1a4e9ed790d62df48bcb675c9f664e9..c25f820e70aba578c5acd3f50d9591c081cfbb73 100644 --- a/src/planner/Maintain.h +++ b/src/planner/Maintain.h @@ -327,7 +327,7 @@ protected: Kind kind, std::string schemaName, std::string indexName, - std::vector<std::string> fields, + std::vector<meta::cpp2::IndexFieldDef> fields, bool ifNotExists) : SingleInputNode(qctx, kind, input), schemaName_(std::move(schemaName)), @@ -344,7 +344,7 @@ public: return indexName_; } - const std::vector<std::string>& getFields() const { + const std::vector<meta::cpp2::IndexFieldDef>& getFields() const { return fields_; } @@ -355,10 +355,10 @@ public: std::unique_ptr<cpp2::PlanNodeDescription> explain() const override; protected: - std::string schemaName_; - std::string indexName_; - std::vector<std::string> fields_; - bool ifNotExists_; + std::string schemaName_; + std::string indexName_; + std::vector<meta::cpp2::IndexFieldDef> fields_; + bool ifNotExists_; }; class CreateTagIndex final : public CreateIndexNode { @@ -367,7 +367,7 @@ public: PlanNode* input, std::string tagName, std::string indexName, - std::vector<std::string> fields, + std::vector<meta::cpp2::IndexFieldDef> fields, bool ifNotExists) { return qctx->objPool()->add(new CreateTagIndex( qctx, input, std::move(tagName), std::move(indexName), std::move(fields), ifNotExists)); @@ -378,7 +378,7 @@ private: PlanNode* input, std::string tagName, std::string indexName, - std::vector<std::string> fields, + std::vector<meta::cpp2::IndexFieldDef> fields, bool ifNotExists) : CreateIndexNode(qctx, input, @@ -395,7 +395,7 @@ public: PlanNode* input, std::string edgeName, std::string indexName, - std::vector<std::string> fields, + std::vector<meta::cpp2::IndexFieldDef> fields, bool ifNotExists) { return qctx->objPool()->add(new CreateEdgeIndex(qctx, input, @@ -410,7 +410,7 @@ private: PlanNode* input, std::string edgeName, std::string indexName, - std::vector<std::string> fields, + std::vector<meta::cpp2::IndexFieldDef> fields, bool ifNotExists) : CreateIndexNode(qctx, input, diff --git a/src/validator/MaintainValidator.cpp b/src/validator/MaintainValidator.cpp index d8fe4ee92a8ee9deeeecd0fdabdc90c436a02ae0..2cab5e537ea5662a98b079d8b4c900cb40e8c4c9 100644 --- a/src/validator/MaintainValidator.cpp +++ b/src/validator/MaintainValidator.cpp @@ -7,7 +7,6 @@ #include "common/base/Base.h" #include "common/charset/Charset.h" #include "common/expression/ConstantExpression.h" - #include "parser/MaintainSentences.h" #include "planner/Maintain.h" #include "planner/Query.h" @@ -303,61 +302,46 @@ Status DropEdgeValidator::toPlan() { } Status CreateTagIndexValidator::validateImpl() { - auto sentence = static_cast<CreateTagIndexSentence *>(sentence_); - tagName_ = *sentence->tagName(); - indexName_ = *sentence->indexName(); - fields_ = sentence->columns(); + auto sentence = static_cast<CreateTagIndexSentence*>(sentence_); + name_ = *sentence->tagName(); + index_ = *sentence->indexName(); + fields_ = sentence->fields(); ifNotExist_ = sentence->isIfNotExist(); - - auto status = Status::OK(); - do { - auto tagStatus = qctx_->schemaMng()->toTagID(space_.id, tagName_); - NG_RETURN_IF_ERROR(tagStatus); - - auto schema_ = qctx_->schemaMng()->getTagSchema(space_.id, tagStatus.value()); - if (schema_ == nullptr) { - return Status::SemanticError("No schema found for '%s'", tagName_.c_str()); - } - - status = IndexUtil::validateColumns(fields_); - if (!status.ok()) { - VLOG(1) << status; - break; - } - } while (false); // TODO(darion) Save the index - return status; + return Status::OK(); } Status CreateTagIndexValidator::toPlan() { - auto *doNode = CreateTagIndex::make(qctx_, nullptr, tagName_, indexName_, fields_, ifNotExist_); + auto sentence = static_cast<CreateTagIndexSentence*>(sentence_); + auto *doNode = CreateTagIndex::make(qctx_, + nullptr, + *sentence->tagName(), + *sentence->indexName(), + sentence->fields(), + sentence->isIfNotExist()); root_ = doNode; tail_ = root_; return Status::OK(); } Status CreateEdgeIndexValidator::validateImpl() { - auto sentence = static_cast<CreateEdgeIndexSentence *>(sentence_); - edgeName_ = *sentence->edgeName(); - indexName_ = *sentence->indexName(); - fields_ = sentence->columns(); + auto sentence = static_cast<CreateEdgeIndexSentence*>(sentence_); + name_ = *sentence->edgeName(); + index_ = *sentence->indexName(); + fields_ = sentence->fields(); ifNotExist_ = sentence->isIfNotExist(); - - auto edgeStatus = qctx_->schemaMng()->toEdgeType(space_.id, edgeName_); - NG_RETURN_IF_ERROR(edgeStatus); - auto schema_ = qctx_->schemaMng()->getEdgeSchema(space_.id, edgeStatus.value()); - if (schema_ == nullptr) { - return Status::SemanticError("No schema found for '%s'", edgeName_.c_str()); - } - - NG_RETURN_IF_ERROR(IndexUtil::validateColumns(fields_)); // TODO(darion) Save the index return Status::OK(); } Status CreateEdgeIndexValidator::toPlan() { - auto *doNode = - CreateEdgeIndex::make(qctx_, nullptr, edgeName_, indexName_, fields_, ifNotExist_); + auto sentence = static_cast<CreateEdgeIndexSentence*>(sentence_); + auto *doNode = CreateEdgeIndex::make(qctx_, + nullptr, + *sentence->edgeName(), + *sentence->indexName(), + sentence->fields(), + sentence->isIfNotExist()); root_ = doNode; tail_ = root_; return Status::OK(); diff --git a/src/validator/MaintainValidator.h b/src/validator/MaintainValidator.h index 41931badfe26a94ac4af267e2f698a900352e24d..7824ea315e934ab258497a1f0c2ca97ebc0d6f3f 100644 --- a/src/validator/MaintainValidator.h +++ b/src/validator/MaintainValidator.h @@ -196,10 +196,10 @@ private: Status toPlan() override; private: - std::string tagName_; - std::string indexName_; - std::vector<std::string> fields_; - bool ifNotExist_; + std::string name_; + std::string index_; + std::vector<meta::cpp2::IndexFieldDef> fields_; + bool ifNotExist_; }; class CreateEdgeIndexValidator final : public Validator { @@ -213,10 +213,10 @@ private: Status toPlan() override; private: - std::string edgeName_; - std::string indexName_; - std::vector<std::string> fields_; - bool ifNotExist_; + std::string name_; + std::string index_; + std::vector<meta::cpp2::IndexFieldDef> fields_; + bool ifNotExist_; }; class DropTagIndexValidator final : public Validator { diff --git a/src/visitor/CollectAllExprsVisitor.h b/src/visitor/CollectAllExprsVisitor.h index 5ea8b05f6a086162f68ee5b2fa64bd56b19e0b45..d86b715b29d581f611313a0c7c9f57c0bdaaa937 100644 --- a/src/visitor/CollectAllExprsVisitor.h +++ b/src/visitor/CollectAllExprsVisitor.h @@ -55,6 +55,8 @@ private: void visit(AttributeExpression* expr) override; void visit(VertexExpression* expr) override; void visit(EdgeExpression* expr) override; + // TODO : CaseExpression + void visit(CaseExpression *) override {}; void visitBinaryExpr(BinaryExpression* expr) override; void collectExpr(const Expression* expr); diff --git a/src/visitor/DeducePropsVisitor.h b/src/visitor/DeducePropsVisitor.h index ae0ecea539b7cab5610558d50fcde2b0e6a9d393..7d11bfd4d00c28ccec301d8cf183375f9066fc1d 100644 --- a/src/visitor/DeducePropsVisitor.h +++ b/src/visitor/DeducePropsVisitor.h @@ -122,6 +122,8 @@ private: void visit(ConstantExpression* expr) override; void visit(VertexExpression* expr) override; void visit(EdgeExpression* expr) override; + // TODO : CaseExpression + void visit(CaseExpression*) override {}; void visitEdgePropExpr(PropertyExpression* expr); void reportError(const Expression* expr); diff --git a/src/visitor/DeduceTypeVisitor.h b/src/visitor/DeduceTypeVisitor.h index 30601bcc4d695d8f894abd69cd262e6e1de68723..deaddcf638dc4fec31fc801f48ac926208bce1b8 100644 --- a/src/visitor/DeduceTypeVisitor.h +++ b/src/visitor/DeduceTypeVisitor.h @@ -73,6 +73,8 @@ private: // vertex/edge expression void visit(VertexExpression *expr) override; void visit(EdgeExpression *expr) override; + // TODO : CaseExpression + void visit(CaseExpression *) override {}; void visitVertexPropertyExpr(PropertyExpression *expr); diff --git a/src/visitor/EvaluableExprVisitor.h b/src/visitor/EvaluableExprVisitor.h index b77f05a0bd9115be638e5fd74dc7cd22b31477b8..1861f004378c4057631dc934641f7cce88ab2c52 100644 --- a/src/visitor/EvaluableExprVisitor.h +++ b/src/visitor/EvaluableExprVisitor.h @@ -89,6 +89,11 @@ private: isEvaluable_ = false; } + // TODO : CaseExpression + void visit(CaseExpression *) override { + isEvaluable_ = false; + } + bool isEvaluable_{true}; }; diff --git a/src/visitor/ExtractFilterExprVisitor.h b/src/visitor/ExtractFilterExprVisitor.h index bf8c1d3afd9f922f458738ff96a718478ab1f971..9f8e96e16587975fa4d7c45f513c564e4b72f8eb 100644 --- a/src/visitor/ExtractFilterExprVisitor.h +++ b/src/visitor/ExtractFilterExprVisitor.h @@ -46,6 +46,8 @@ private: void visit(VertexExpression *) override; void visit(EdgeExpression *) override; void visit(LogicalExpression *) override; + // TODO : CaseExpression + void visit(CaseExpression *) override {}; bool canBePushed_{true}; std::unique_ptr<Expression> remainedExpr_; diff --git a/src/visitor/ExtractPropExprVisitor.h b/src/visitor/ExtractPropExprVisitor.h index d5c521f9c59ebe090149972f2d69d6642fbd96e7..d01351dfa9c26ae9a99338a3f821a00f44060f9e 100644 --- a/src/visitor/ExtractPropExprVisitor.h +++ b/src/visitor/ExtractPropExprVisitor.h @@ -60,6 +60,8 @@ private: void visit(EdgeExpression *) override; // binary expression void visit(SubscriptExpression *) override; + // TODO : CaseExpression + void visit(CaseExpression *) override {}; void visitVertexEdgePropExpr(PropertyExpression *); void visitPropertyExpr(PropertyExpression *); diff --git a/src/visitor/FindAnyExprVisitor.h b/src/visitor/FindAnyExprVisitor.h index 580ec33872cafd581fe73c4315e4cd019f8edbd6..23727a461f058136d51cf3a49cc750285668b767 100644 --- a/src/visitor/FindAnyExprVisitor.h +++ b/src/visitor/FindAnyExprVisitor.h @@ -55,6 +55,8 @@ private: void visit(LabelExpression* expr) override; void visit(VertexExpression* expr) override; void visit(EdgeExpression* expr) override; + // TODO : CaseExpression + void visit(CaseExpression*) override {}; void visitBinaryExpr(BinaryExpression* expr) override; diff --git a/src/visitor/FoldConstantExprVisitor.h b/src/visitor/FoldConstantExprVisitor.h index a99ae13abc00e57e37dd4e7f29c52305b678d04a..04be0cad2ac06b4b7cdfdbb65ff49783e4213ac7 100644 --- a/src/visitor/FoldConstantExprVisitor.h +++ b/src/visitor/FoldConstantExprVisitor.h @@ -53,6 +53,8 @@ public: // vertex/edge expression void visit(VertexExpression *expr) override; void visit(EdgeExpression *expr) override; + // TODO : CaseExpression + void visit(CaseExpression*) override {}; void visitBinaryExpr(BinaryExpression *expr); Expression *fold(Expression *expr) const; diff --git a/src/visitor/RewriteInputPropVisitor.h b/src/visitor/RewriteInputPropVisitor.h index 6e4500c51316e613fe30ce1b75b941a027abfc4d..cac274e23b16ab0a36f66f78b6f2ebb687b3223e 100644 --- a/src/visitor/RewriteInputPropVisitor.h +++ b/src/visitor/RewriteInputPropVisitor.h @@ -68,6 +68,7 @@ private: // vertex/edge expression void visit(VertexExpression *) override; void visit(EdgeExpression *) override; + void visit(CaseExpression*) override {}; void visitBinaryExpr(BinaryExpression *expr); diff --git a/src/visitor/RewriteLabelAttrVisitor.h b/src/visitor/RewriteLabelAttrVisitor.h index 03020503527e8375cca344b500f25eecda02104e..a6b5795defd68baef69dfe4b81ff05678b13f417 100644 --- a/src/visitor/RewriteLabelAttrVisitor.h +++ b/src/visitor/RewriteLabelAttrVisitor.h @@ -50,6 +50,8 @@ private: void visit(EdgeDstIdExpression *) override {} void visit(VertexExpression *) override {} void visit(EdgeExpression *) override {} + // TODO : CaseExpression + void visit(CaseExpression *) override {} void visitBinaryExpr(BinaryExpression *expr) override; diff --git a/src/visitor/RewriteMatchLabelVisitor.h b/src/visitor/RewriteMatchLabelVisitor.h index fc83b490811a0db9710f0df24dbe39a11e495426..af14ec081262b9e871f804b66afade07ab076566 100644 --- a/src/visitor/RewriteMatchLabelVisitor.h +++ b/src/visitor/RewriteMatchLabelVisitor.h @@ -58,6 +58,8 @@ private: void visit(EdgeDstIdExpression*) override {} void visit(VertexExpression*) override {} void visit(EdgeExpression*) override {} + // TODO : CaseExpression + void visit(CaseExpression*) override {} void visitBinaryExpr(BinaryExpression *) override; diff --git a/src/visitor/RewriteSymExprVisitor.h b/src/visitor/RewriteSymExprVisitor.h index 53a29592946f73dcd5de8ba6b0ab308632daed66..40b44d9f6910c8f4105f3e6c0303e4eb56fcc2eb 100644 --- a/src/visitor/RewriteSymExprVisitor.h +++ b/src/visitor/RewriteSymExprVisitor.h @@ -64,6 +64,8 @@ public: // vertex/edge expression void visit(VertexExpression *expr) override; void visit(EdgeExpression *expr) override; + // TODO : CaseExpression + void visit(CaseExpression*) override {}; private: void visitBinaryExpr(BinaryExpression *expr); diff --git a/tests/data/nba.ngql b/tests/data/nba.ngql index d994dd8992ed664b4d992820912c5f84dadad56a..a1e4402fcab3fbef4ddc127a95aaf574f6ebde48 100644 --- a/tests/data/nba.ngql +++ b/tests/data/nba.ngql @@ -14,11 +14,11 @@ CREATE EDGE IF NOT EXISTS teammate(start_year int, end_year int); --END --DDL -CREATE TAG INDEX IF NOT EXISTS player_name_index ON player(name); +CREATE TAG INDEX IF NOT EXISTS player_name_index ON player(name(64)); CREATE TAG INDEX IF NOT EXISTS player_age_index ON player(age); -CREATE TAG INDEX IF NOT EXISTS team_name_index ON team(name); +CREATE TAG INDEX IF NOT EXISTS team_name_index ON team(name(64)); --END