diff --git a/.github/workflows/check_label.yml b/.github/workflows/check_label.yml new file mode 100644 index 00000000000..e410727ab99 --- /dev/null +++ b/.github/workflows/check_label.yml @@ -0,0 +1,22 @@ +name: Auto label + +on: + issues: + types: + - reopened + - opened + - labeled + - unlabeled + - closed + +env: + GH_PAT: ${{ secrets.GITHUB_TOKEN }} + EVENT: ${{ toJSON(github.event)}} + EVENT_NAME: ${{ github.event_name}} + +jobs: + sync: + name: auto label + runs-on: ubuntu-latest + steps: + - uses: HarrisChu/auto_label@v1 diff --git a/src/clients/meta/MetaClient.cpp b/src/clients/meta/MetaClient.cpp index 8e095331603..ddaa64fd897 100644 --- a/src/clients/meta/MetaClient.cpp +++ b/src/clients/meta/MetaClient.cpp @@ -829,13 +829,13 @@ Status MetaClient::handleResponse(const RESP& resp) { case nebula::cpp2::ErrorCode::E_EXISTED: return Status::Error("Existed!"); case nebula::cpp2::ErrorCode::E_SPACE_NOT_FOUND: - return Status::Error("Space not existed!"); + return Status::SpaceNotFound("Space not existed!"); case nebula::cpp2::ErrorCode::E_TAG_NOT_FOUND: - return Status::Error("Tag not existed!"); + return Status::TagNotFound("Tag not existed!"); case nebula::cpp2::ErrorCode::E_EDGE_NOT_FOUND: - return Status::Error("Edge not existed!"); + return Status::EdgeNotFound("Edge not existed!"); case nebula::cpp2::ErrorCode::E_INDEX_NOT_FOUND: - return Status::Error("Index not existed!"); + return Status::IndexNotFound("Index not existed!"); case nebula::cpp2::ErrorCode::E_STATS_NOT_FOUND: return Status::Error( "There is no any stats info to show, please execute " @@ -1389,7 +1389,7 @@ StatusOr MetaClient::getSpaceIdByNameFromCache(const std::string& if (it != metadata.spaceIndexByName_.end()) { return it->second; } - return Status::SpaceNotFound(); + return Status::SpaceNotFound(fmt::format("SpaceName `{}`", name)); } StatusOr MetaClient::getSpaceNameByIdFromCache(GraphSpaceID spaceId) { @@ -1401,7 +1401,7 @@ StatusOr MetaClient::getSpaceNameByIdFromCache(GraphSpaceID spaceId auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { LOG(ERROR) << "Space " << spaceId << " not found!"; - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } return spaceIt->second->spaceDesc_.get_space_name(); } @@ -1415,7 +1415,7 @@ StatusOr MetaClient::getTagIDByNameFromCache(const GraphSpaceID& space, const auto& metadata = *metadata_.load(); auto it = metadata.spaceTagIndexByName_.find(std::make_pair(space, name)); if (it == metadata.spaceTagIndexByName_.end()) { - return Status::Error("TagName `%s' is nonexistent", name.c_str()); + return Status::TagNotFound(fmt::format("TagName `{}`", name)); } return it->second; } @@ -1429,7 +1429,7 @@ StatusOr MetaClient::getTagNameByIdFromCache(const GraphSpaceID& sp const auto& metadata = *metadata_.load(); auto it = metadata.spaceTagIndexById_.find(std::make_pair(space, tagId)); if (it == metadata.spaceTagIndexById_.end()) { - return Status::Error("TagID `%d' is nonexistent", tagId); + return Status::TagNotFound(fmt::format("TagID `{}`", tagId)); } return it->second; } @@ -1443,7 +1443,7 @@ StatusOr MetaClient::getEdgeTypeByNameFromCache(const GraphSpaceID& sp const auto& metadata = *metadata_.load(); auto it = metadata.spaceEdgeIndexByName_.find(std::make_pair(space, name)); if (it == metadata.spaceEdgeIndexByName_.end()) { - return Status::Error("EdgeName `%s' is nonexistent", name.c_str()); + return Status::EdgeNotFound(fmt::format("EdgeName `{}`", name)); } return it->second; } @@ -1457,7 +1457,7 @@ StatusOr MetaClient::getEdgeNameByTypeFromCache(const GraphSpaceID& const auto& metadata = *metadata_.load(); auto it = metadata.spaceEdgeIndexByType_.find(std::make_pair(space, edgeType)); if (it == metadata.spaceEdgeIndexByType_.end()) { - return Status::Error("EdgeType `%d' is nonexistent", edgeType); + return Status::EdgeNotFound(fmt::format("EdgeType `{}`", edgeType)); } return it->second; } @@ -1470,7 +1470,7 @@ StatusOr> MetaClient::getAllEdgeFromCache(const GraphSp const auto& metadata = *metadata_.load(); auto it = metadata.spaceAllEdgeMap_.find(space); if (it == metadata.spaceAllEdgeMap_.end()) { - return Status::Error("SpaceId `%d' is nonexistent", space); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", space)); } return it->second; } @@ -1542,7 +1542,7 @@ StatusOr MetaClient::partsNum(GraphSpaceID spaceId) { const auto& metadata = *metadata_.load(); auto it = metadata.localCache_.find(spaceId); if (it == metadata.localCache_.end()) { - return Status::Error("Space not found, spaceid: %d", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } return it->second->partsAlloc_.size(); } @@ -1937,7 +1937,7 @@ StatusOr MetaClient::getSpaceVidLen(const GraphSpaceID& spaceId) { auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { LOG(ERROR) << "Space " << spaceId << " not found!"; - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } auto& vidType = spaceIt->second->spaceDesc_.get_vid_type(); auto vIdLen = vidType.type_length_ref().has_value() ? *vidType.get_type_length() : 0; @@ -1956,7 +1956,7 @@ StatusOr MetaClient::getSpaceVidType(const GraphSpac auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { LOG(ERROR) << "Space " << spaceId << " not found!"; - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } auto vIdType = spaceIt->second->spaceDesc_.get_vid_type().get_type(); if (vIdType != nebula::cpp2::PropertyType::INT64 && @@ -1969,16 +1969,16 @@ StatusOr MetaClient::getSpaceVidType(const GraphSpac return vIdType; } -StatusOr MetaClient::getSpaceDesc(const GraphSpaceID& space) { +StatusOr MetaClient::getSpaceDesc(const GraphSpaceID& spaceId) { if (!ready_) { return Status::Error("Not ready!"); } folly::rcu_reader guard; const auto& metadata = *metadata_.load(); - auto spaceIt = metadata.localCache_.find(space); + auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { - LOG(ERROR) << "Space " << space << " not found!"; - return Status::Error("Space %d not found", space); + LOG(ERROR) << "Space " << spaceId << " not found!"; + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } return spaceIt->second->spaceDesc_; } @@ -2042,7 +2042,7 @@ StatusOr MetaClient::getAllVerTagSchema(GraphSpaceID spaceId) { const auto& metadata = *metadata_.load(); auto iter = metadata.localCache_.find(spaceId); if (iter == metadata.localCache_.end()) { - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } return iter->second->tagSchemas_; } @@ -2055,7 +2055,7 @@ StatusOr MetaClient::getAllLatestVerTagSchema(const GraphSpaceID& spa const auto& metadata = *metadata_.load(); auto iter = metadata.localCache_.find(spaceId); if (iter == metadata.localCache_.end()) { - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } TagSchema tagsSchema; tagsSchema.reserve(iter->second->tagSchemas_.size()); @@ -2074,7 +2074,7 @@ StatusOr MetaClient::getAllVerEdgeSchema(GraphSpaceID spaceId) { const auto& metadata = *metadata_.load(); auto iter = metadata.localCache_.find(spaceId); if (iter == metadata.localCache_.end()) { - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } return iter->second->edgeSchemas_; } @@ -2087,7 +2087,7 @@ StatusOr MetaClient::getAllLatestVerEdgeSchemaFromCache(const GraphS const auto& metadata = *metadata_.load(); auto iter = metadata.localCache_.find(spaceId); if (iter == metadata.localCache_.end()) { - return Status::Error("Space %d not found", spaceId); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } EdgeSchema edgesSchema; edgesSchema.reserve(iter->second->edgeSchemas_.size()); @@ -2140,7 +2140,7 @@ StatusOr> MetaClient::getTagIndexByNameFromCach std::pair key(space, name); auto iter = tagNameIndexMap_.find(key); if (iter == tagNameIndexMap_.end()) { - return Status::IndexNotFound(); + return Status::IndexNotFound(fmt::format("Index: {}:{}", space, name)); } auto indexID = iter->second; auto itemStatus = getTagIndexFromCache(space, indexID); @@ -2158,7 +2158,7 @@ StatusOr> MetaClient::getEdgeIndexByNameFromCac std::pair key(space, name); auto iter = edgeNameIndexMap_.find(key); if (iter == edgeNameIndexMap_.end()) { - return Status::IndexNotFound(); + return Status::IndexNotFound(fmt::format("Index: {}:{}", space, name)); } auto indexID = iter->second; auto itemStatus = getEdgeIndexFromCache(space, indexID); @@ -2179,7 +2179,7 @@ StatusOr> MetaClient::getTagIndexFromCache(Grap auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { VLOG(3) << "Space " << spaceId << " not found!"; - return Status::SpaceNotFound(); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } else { auto iter = spaceIt->second->tagIndexes_.find(indexID); if (iter == spaceIt->second->tagIndexes_.end()) { @@ -2207,7 +2207,7 @@ StatusOr MetaClient::getRelatedTagIDByIndexNameFromCache(const GraphSpace } StatusOr> MetaClient::getEdgeIndexFromCache(GraphSpaceID spaceId, - IndexID indexID) { + IndexID indexId) { if (!ready_) { return Status::Error("Not ready!"); } @@ -2217,12 +2217,12 @@ StatusOr> MetaClient::getEdgeIndexFromCache(Gra auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { VLOG(3) << "Space " << spaceId << " not found!"; - return Status::SpaceNotFound(); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } else { - auto iter = spaceIt->second->edgeIndexes_.find(indexID); + auto iter = spaceIt->second->edgeIndexes_.find(indexId); if (iter == spaceIt->second->edgeIndexes_.end()) { - VLOG(3) << "Space " << spaceId << ", Edge Index " << indexID << " not found!"; - return Status::IndexNotFound(); + VLOG(3) << "Space " << spaceId << ", Edge Index " << indexId << " not found!"; + return Status::IndexNotFound(fmt::format("Index: {}:{}", spaceId, indexId)); } else { return iter->second; } @@ -2255,7 +2255,7 @@ StatusOr>> MetaClient::getTagIndexe auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { VLOG(3) << "Space " << spaceId << " not found!"; - return Status::SpaceNotFound(); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } else { auto tagIndexes = spaceIt->second->tagIndexes_; auto iter = tagIndexes.begin(); @@ -2279,7 +2279,7 @@ StatusOr>> MetaClient::getEdgeIndex auto spaceIt = metadata.localCache_.find(spaceId); if (spaceIt == metadata.localCache_.end()) { VLOG(3) << "Space " << spaceId << " not found!"; - return Status::SpaceNotFound(); + return Status::SpaceNotFound(fmt::format("SpaceId `{}`", spaceId)); } else { auto edgeIndexes = spaceIt->second->edgeIndexes_; auto iter = edgeIndexes.begin(); @@ -2490,7 +2490,7 @@ StatusOr MetaClient::getLatestEdgeVersionFromCache(const GraphSpaceID const auto& metadata = *metadata_.load(); auto it = metadata.spaceNewestEdgeVerMap_.find(std::make_pair(space, edgeType)); if (it == metadata.spaceNewestEdgeVerMap_.end()) { - return Status::EdgeNotFound(); + return Status::EdgeNotFound(fmt::format("EdgeType `{}`", edgeType)); } return it->second; } diff --git a/src/codec/RowReaderV1.cpp b/src/codec/RowReaderV1.cpp index 877e1e35cee..b56b831a228 100644 --- a/src/codec/RowReaderV1.cpp +++ b/src/codec/RowReaderV1.cpp @@ -198,11 +198,11 @@ Value RowReaderV1::getValueByName(const std::string& prop) const noexcept { Value RowReaderV1::getValueByIndex(const int64_t index) const noexcept { if (index < 0 || static_cast(index) >= schema_->getNumFields()) { - return Value(NullType::UNKNOWN_PROP); + return Value(NullType::__NULL__); } auto vType = getSchema()->getFieldType(index); if (PropertyType::UNKNOWN == vType) { - return Value(NullType::UNKNOWN_PROP); + return Value(NullType::__NULL__); } switch (vType) { case PropertyType::BOOL: diff --git a/src/codec/RowReaderV2.cpp b/src/codec/RowReaderV2.cpp index fc213cbf568..91db3933fec 100644 --- a/src/codec/RowReaderV2.cpp +++ b/src/codec/RowReaderV2.cpp @@ -52,7 +52,7 @@ Value RowReaderV2::getValueByName(const std::string& prop) const noexcept { Value RowReaderV2::getValueByIndex(const int64_t index) const noexcept { if (index < 0 || static_cast(index) >= schema_->getNumFields()) { - return Value(NullType::UNKNOWN_PROP); + return Value(NullType::__NULL__); } auto field = schema_->field(index); diff --git a/src/common/datatypes/Map.h b/src/common/datatypes/Map.h index 91134a48387..9a55f28318c 100644 --- a/src/common/datatypes/Map.h +++ b/src/common/datatypes/Map.h @@ -69,7 +69,7 @@ struct Map { const Value& at(const std::string& key) const { auto iter = kvs.find(key); if (iter == kvs.end()) { - return Value::kNullUnknownProp; + return Value::kNullValue; } return iter->second; } diff --git a/src/common/datatypes/Value.cpp b/src/common/datatypes/Value.cpp index 7de3ece5103..c49adf90290 100644 --- a/src/common/datatypes/Value.cpp +++ b/src/common/datatypes/Value.cpp @@ -29,7 +29,6 @@ const Value Value::kNullNaN(NullType::NaN); const Value Value::kNullBadData(NullType::BAD_DATA); const Value Value::kNullBadType(NullType::BAD_TYPE); const Value Value::kNullOverflow(NullType::ERR_OVERFLOW); -const Value Value::kNullUnknownProp(NullType::UNKNOWN_PROP); const Value Value::kNullDivByZero(NullType::DIV_BY_ZERO); const Value Value::kNullOutOfRange(NullType::OUT_OF_RANGE); @@ -320,7 +319,6 @@ const std::string& Value::typeName() const { {NullType::BAD_DATA, "BAD_DATA"}, {NullType::BAD_TYPE, "BAD_TYPE"}, {NullType::ERR_OVERFLOW, "ERR_OVERFLOW"}, - {NullType::UNKNOWN_PROP, "UNKNOWN_PROP"}, {NullType::DIV_BY_ZERO, "DIV_BY_ZERO"}, }; @@ -1564,8 +1562,6 @@ std::string Value::toString() const { return "__NULL_OVERFLOW__"; case NullType::NaN: return "__NULL_NaN__"; - case NullType::UNKNOWN_PROP: - return "__NULL_UNKNOWN_PROP__"; case NullType::OUT_OF_RANGE: return "__NULL_OUT_OF_RANGE__"; } diff --git a/src/common/datatypes/Value.h b/src/common/datatypes/Value.h index 06f4e8b2241..b55397a1566 100644 --- a/src/common/datatypes/Value.h +++ b/src/common/datatypes/Value.h @@ -40,7 +40,6 @@ enum class NullType { BAD_DATA = 2, BAD_TYPE = 3, ERR_OVERFLOW = 4, - UNKNOWN_PROP = 5, DIV_BY_ZERO = 6, OUT_OF_RANGE = 7, }; @@ -52,7 +51,6 @@ struct Value { static const Value kNullBadData; static const Value kNullBadType; static const Value kNullOverflow; - static const Value kNullUnknownProp; static const Value kNullDivByZero; static const Value kNullOutOfRange; @@ -157,8 +155,8 @@ struct Value { } auto& null = value_.nVal; return null == NullType::NaN || null == NullType::BAD_DATA || null == NullType::BAD_TYPE || - null == NullType::ERR_OVERFLOW || null == NullType::UNKNOWN_PROP || - null == NullType::DIV_BY_ZERO || null == NullType::OUT_OF_RANGE; + null == NullType::ERR_OVERFLOW || null == NullType::DIV_BY_ZERO || + null == NullType::OUT_OF_RANGE; } bool isNumeric() const { return type_ == Type::INT || type_ == Type::FLOAT; diff --git a/src/common/datatypes/test/ValueTest.cpp b/src/common/datatypes/test/ValueTest.cpp index 73abce84640..571c74f463f 100644 --- a/src/common/datatypes/test/ValueTest.cpp +++ b/src/common/datatypes/test/ValueTest.cpp @@ -1565,7 +1565,6 @@ TEST(Value, typeName) { EXPECT_EQ("BAD_DATA", Value::kNullBadData.typeName()); EXPECT_EQ("BAD_TYPE", Value::kNullBadType.typeName()); EXPECT_EQ("ERR_OVERFLOW", Value::kNullOverflow.typeName()); - EXPECT_EQ("UNKNOWN_PROP", Value::kNullUnknownProp.typeName()); EXPECT_EQ("DIV_BY_ZERO", Value::kNullDivByZero.typeName()); } @@ -1582,7 +1581,6 @@ TEST(Value, DecodeEncode) { Value(NullType::BAD_DATA), Value(NullType::ERR_OVERFLOW), Value(NullType::OUT_OF_RANGE), - Value(NullType::UNKNOWN_PROP), // int Value(0), diff --git a/src/common/datatypes/test/ValueToJsonTest.cpp b/src/common/datatypes/test/ValueToJsonTest.cpp index 457b666051d..a2e8923e2a5 100644 --- a/src/common/datatypes/test/ValueToJsonTest.cpp +++ b/src/common/datatypes/test/ValueToJsonTest.cpp @@ -225,7 +225,7 @@ TEST(ValueToJson, DecodeEncode) { Value(NullType::BAD_DATA), Value(NullType::ERR_OVERFLOW), Value(NullType::OUT_OF_RANGE), - Value(NullType::UNKNOWN_PROP), + Value(NullType::__NULL__), // int Value(0), diff --git a/src/common/expression/AttributeExpression.cpp b/src/common/expression/AttributeExpression.cpp index 92425be7892..4f8f7b9c147 100644 --- a/src/common/expression/AttributeExpression.cpp +++ b/src/common/expression/AttributeExpression.cpp @@ -33,7 +33,7 @@ const Value &AttributeExpression::eval(ExpressionContext &ctx) { return iter->second; } } - return Value::kNullUnknownProp; + return Value::kNullValue; } case Value::Type::EDGE: { DCHECK(!rvalue.getStr().empty()); diff --git a/src/common/expression/test/AttributeExpressionTest.cpp b/src/common/expression/test/AttributeExpressionTest.cpp index 5b3dbbe5870..1258e953bfa 100644 --- a/src/common/expression/test/AttributeExpressionTest.cpp +++ b/src/common/expression/test/AttributeExpressionTest.cpp @@ -134,7 +134,7 @@ TEST_F(AttributeExpressionTest, DateTimeAttribute) { auto *right = LabelExpression::make(&pool, "not exist attribute"); auto expr = AttributeExpression::make(&pool, left, right); auto value = Expression::eval(expr, gExpCtxt); - ASSERT_EQ(Value::kNullUnknownProp, value); + ASSERT_EQ(Value::kNullValue, value); } { auto *left = ConstantExpression::make(&pool, Value(dt)); @@ -148,7 +148,7 @@ TEST_F(AttributeExpressionTest, DateTimeAttribute) { auto *right = LabelExpression::make(&pool, "not exist attribute"); auto expr = AttributeExpression::make(&pool, left, right); auto value = Expression::eval(expr, gExpCtxt); - ASSERT_EQ(Value::kNullUnknownProp, value); + ASSERT_EQ(Value::kNullValue, value); } { auto *left = ConstantExpression::make(&pool, Value(d)); @@ -162,7 +162,7 @@ TEST_F(AttributeExpressionTest, DateTimeAttribute) { auto *right = LabelExpression::make(&pool, "not exist attribute"); auto expr = AttributeExpression::make(&pool, left, right); auto value = Expression::eval(expr, gExpCtxt); - ASSERT_EQ(Value::kNullUnknownProp, value); + ASSERT_EQ(Value::kNullValue, value); } { auto *left = ConstantExpression::make(&pool, Value(t)); diff --git a/src/common/expression/test/SubscriptExpressionTest.cpp b/src/common/expression/test/SubscriptExpressionTest.cpp index 622557d7b5a..7d7f7ead0cf 100644 --- a/src/common/expression/test/SubscriptExpressionTest.cpp +++ b/src/common/expression/test/SubscriptExpressionTest.cpp @@ -338,7 +338,6 @@ TEST_F(SubscriptExpressionTest, MapSubscript) { auto expr = SubscriptExpression::make(&pool, map, key); auto value = Expression::eval(expr, gExpCtxt); ASSERT_TRUE(value.isNull()); - ASSERT_TRUE(value.isBadNull()); } // {"key1":1,"key2":2, "key3":3}[0] { diff --git a/src/common/time/TimeUtils.h b/src/common/time/TimeUtils.h index 94570877ad3..e2c4bba09ed 100644 --- a/src/common/time/TimeUtils.h +++ b/src/common/time/TimeUtils.h @@ -124,7 +124,7 @@ class TimeUtils { } else if (lowerProp == "microsecond") { return static_cast(dt.microsec); } else { - return Value::kNullUnknownProp; + return Value::kNullValue; } } @@ -160,7 +160,7 @@ class TimeUtils { } else if (lowerProp == "day") { return d.day; } else { - return Value::kNullUnknownProp; + return Value::kNullValue; } } @@ -203,7 +203,7 @@ class TimeUtils { } else if (lowerProp == "microsecond") { return t.microsec; } else { - return Value::kNullUnknownProp; + return Value::kNullValue; } } diff --git a/src/common/utils/IndexKeyUtils.cpp b/src/common/utils/IndexKeyUtils.cpp index 3707d85f52e..5e984ddb54e 100644 --- a/src/common/utils/IndexKeyUtils.cpp +++ b/src/common/utils/IndexKeyUtils.cpp @@ -204,7 +204,7 @@ StatusOr IndexKeyUtils::readValueWithLatestSche(RowReader* reader, const std::string propName, const meta::SchemaProviderIf* latestSchema) { auto value = reader->getValueByName(propName); - if (latestSchema == nullptr || !value.isNull() || value.getNull() != NullType::UNKNOWN_PROP) { + if (latestSchema == nullptr || !value.isNull() || value.getNull() != NullType::__NULL__) { return value; } auto field = latestSchema->field(propName); @@ -230,9 +230,6 @@ Status IndexKeyUtils::checkValue(const Value& v, bool isNullable) { } switch (v.getNull()) { - case nebula::NullType::UNKNOWN_PROP: { - return Status::Error("Unknown prop"); - } case nebula::NullType::__NULL__: { if (!isNullable) { return Status::Error("Not allowed to be null"); diff --git a/src/daemons/CMakeLists.txt b/src/daemons/CMakeLists.txt index 1b2665e2941..4e88107b8b1 100644 --- a/src/daemons/CMakeLists.txt +++ b/src/daemons/CMakeLists.txt @@ -45,6 +45,7 @@ set(storage_meta_deps $ $ $ + $ $ $ $ diff --git a/src/graph/context/ast/QueryAstContext.h b/src/graph/context/ast/QueryAstContext.h index 8850c435ff6..f50658a439b 100644 --- a/src/graph/context/ast/QueryAstContext.h +++ b/src/graph/context/ast/QueryAstContext.h @@ -132,6 +132,7 @@ struct SubgraphContext final : public AstContext { Expression* tagFilter{nullptr}; Expression* edgeFilter{nullptr}; std::vector colNames; + std::unordered_set edgeNames; std::unordered_set edgeTypes; std::unordered_set biDirectEdgeTypes; std::vector colType; diff --git a/src/graph/executor/logic/ArgumentExecutor.cpp b/src/graph/executor/logic/ArgumentExecutor.cpp index 0909c9fce65..61b4c6b6cbd 100644 --- a/src/graph/executor/logic/ArgumentExecutor.cpp +++ b/src/graph/executor/logic/ArgumentExecutor.cpp @@ -23,7 +23,7 @@ folly::Future ArgumentExecutor::execute() { ds.rows.reserve(iter->size()); std::unordered_set unique; for (; iter->valid(); iter->next()) { - auto val = iter->getColumn(alias); + auto &val = iter->getColumn(alias); if (!val.isVertex()) { return Status::Error("Argument only support vertex, but got %s, which is type %s, ", val.toString().c_str(), @@ -31,7 +31,7 @@ folly::Future ArgumentExecutor::execute() { } if (unique.emplace(val.getVertex().vid).second) { Row row; - row.values.emplace_back(std::move(val)); + row.values.emplace_back(val); ds.rows.emplace_back(std::move(row)); } } diff --git a/src/graph/planner/match/MatchPathPlanner.cpp b/src/graph/planner/match/MatchPathPlanner.cpp index f5e5c96cf45..508bfbcac6d 100644 --- a/src/graph/planner/match/MatchPathPlanner.cpp +++ b/src/graph/planner/match/MatchPathPlanner.cpp @@ -11,6 +11,7 @@ #include "graph/planner/match/WhereClausePlanner.h" #include "graph/planner/plan/Algo.h" #include "graph/planner/plan/Logic.h" +#include "graph/planner/plan/PlanNode.h" #include "graph/planner/plan/Query.h" #include "graph/util/ExpressionUtils.h" #include "graph/util/SchemaUtil.h" @@ -131,9 +132,7 @@ Status MatchPathPlanner::findStarts( auto nodeFinder = finder(); if (nodeFinder->match(&nodeCtx)) { auto plan = nodeFinder->transform(&nodeCtx); - if (!plan.ok()) { - return plan.status(); - } + NG_RETURN_IF_ERROR(plan); matchClausePlan = std::move(plan).value(); startIndex = i; foundStart = true; @@ -149,9 +148,7 @@ Status MatchPathPlanner::findStarts( auto edgeFinder = finder(); if (edgeFinder->match(&edgeCtx)) { auto plan = edgeFinder->transform(&edgeCtx); - if (!plan.ok()) { - return plan.status(); - } + NG_RETURN_IF_ERROR(plan); matchClausePlan = std::move(plan).value(); startFromEdge = true; startIndex = i; @@ -169,7 +166,9 @@ Status MatchPathPlanner::findStarts( return Status::SemanticError("Can't solve the start vids from the sentence."); } - if (matchClausePlan.tail->isSingleInput()) { + // Both StartNode and Argument are leaf plannodes + if (matchClausePlan.tail->isSingleInput() && + matchClausePlan.tail->kind() != PlanNode::Kind::kArgument) { auto start = StartNode::make(qctx); matchClausePlan.tail->setDep(0, start); matchClausePlan.tail = start; diff --git a/src/graph/planner/match/MatchPlanner.cpp b/src/graph/planner/match/MatchPlanner.cpp index 0a23cd31e1e..474d68fac5c 100644 --- a/src/graph/planner/match/MatchPlanner.cpp +++ b/src/graph/planner/match/MatchPlanner.cpp @@ -88,6 +88,11 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma } } if (!intersectedAliases.empty()) { + if (matchPlan.tail->kind() == PlanNode::Kind::kArgument) { + // The input of the argument operator is always the output of the plan on the other side of + // the join + matchPlan.tail->setInputVar(queryPlan.root->outputVar()); + } if (matchCtx->isOptional) { // connect LeftJoin match filter auto& whereCtx = matchCtx->where; diff --git a/src/graph/planner/match/ShortestPathPlanner.cpp b/src/graph/planner/match/ShortestPathPlanner.cpp index 5eef293a7ca..090305e2518 100644 --- a/src/graph/planner/match/ShortestPathPlanner.cpp +++ b/src/graph/planner/match/ShortestPathPlanner.cpp @@ -79,9 +79,12 @@ StatusOr ShortestPathPlanner::transform( auto status = nodeFinder->transform(&nodeCtx); NG_RETURN_IF_ERROR(status); auto plan = status.value(); - auto start = StartNode::make(qctx); - plan.tail->setDep(0, start); - plan.tail = start; + if (plan.tail->kind() != PlanNode::Kind::kStart && + plan.tail->kind() != PlanNode::Kind::kArgument) { + auto start = StartNode::make(qctx); + plan.tail->setDep(0, start); + plan.tail = start; + } auto initExpr = nodeCtx.initialExpr->clone(); auto columns = qctx->objPool()->makeAndAdd(); diff --git a/src/graph/planner/plan/Logic.cpp b/src/graph/planner/plan/Logic.cpp index 67d30e0c49d..824af27ebc9 100644 --- a/src/graph/planner/plan/Logic.cpp +++ b/src/graph/planner/plan/Logic.cpp @@ -69,8 +69,7 @@ std::unique_ptr Select::explain() const { return desc; } -Argument::Argument(QueryContext* qctx, std::string alias, const PlanNode* dep) - : SingleInputNode(qctx, Kind::kArgument, dep) { +Argument::Argument(QueryContext* qctx, std::string alias) : PlanNode(qctx, Kind::kArgument) { alias_ = alias; // An argument is a kind of leaf node, it has no dependencies but read a variable. inputVars_.emplace_back(nullptr); diff --git a/src/graph/planner/plan/Logic.h b/src/graph/planner/plan/Logic.h index a8cbd9f791a..f503bf1aae5 100644 --- a/src/graph/planner/plan/Logic.h +++ b/src/graph/planner/plan/Logic.h @@ -147,10 +147,10 @@ class PassThroughNode final : public SingleInputNode { }; // This operator is used for getting a named alias from another executed operator. -class Argument final : public SingleInputNode { +class Argument final : public PlanNode { public: - static Argument* make(QueryContext* qctx, std::string alias, const PlanNode* dep = nullptr) { - return qctx->objPool()->makeAndAdd(qctx, alias, dep); + static Argument* make(QueryContext* qctx, std::string alias) { + return qctx->objPool()->makeAndAdd(qctx, alias); } PlanNode* clone() const override; @@ -163,7 +163,7 @@ class Argument final : public SingleInputNode { private: friend ObjectPool; - Argument(QueryContext* qctx, std::string alias, const PlanNode* dep = nullptr); + Argument(QueryContext* qctx, std::string alias); void cloneMembers(const Argument&); diff --git a/src/graph/util/ExpressionUtils.cpp b/src/graph/util/ExpressionUtils.cpp index cb20cfcadf0..476e3381416 100644 --- a/src/graph/util/ExpressionUtils.cpp +++ b/src/graph/util/ExpressionUtils.cpp @@ -758,6 +758,14 @@ void ExpressionUtils::pullOrs(Expression *expr) { logic->setOperands(std::move(operands)); } +void ExpressionUtils::pullXors(Expression *expr) { + DCHECK(expr->kind() == Expression::Kind::kLogicalXor); + auto *logic = static_cast(expr); + std::vector operands; + pullXorsImpl(logic, operands); + logic->setOperands(std::move(operands)); +} + void ExpressionUtils::pullAndsImpl(LogicalExpression *expr, std::vector &operands) { for (auto &operand : expr->operands()) { if (operand->kind() != Expression::Kind::kLogicalAnd) { @@ -778,6 +786,16 @@ void ExpressionUtils::pullOrsImpl(LogicalExpression *expr, std::vector &operands) { + for (auto &operand : expr->operands()) { + if (operand->kind() != Expression::Kind::kLogicalXor) { + operands.emplace_back(std::move(operand)); + continue; + } + pullXorsImpl(static_cast(operand), operands); + } +} + Expression *ExpressionUtils::flattenInnerLogicalAndExpr(const Expression *expr) { auto matcher = [](const Expression *e) -> bool { return e->kind() == Expression::Kind::kLogicalAnd; @@ -1094,8 +1112,12 @@ LogicalExpression *ExpressionUtils::reverseLogicalExpr(LogicalExpression *expr) std::vector operands; if (expr->kind() == Expression::Kind::kLogicalAnd) { pullAnds(expr); - } else { + } else if (expr->kind() == Expression::Kind::kLogicalOr) { pullOrs(expr); + } else if (expr->kind() == Expression::Kind::kLogicalXor) { + pullXors(expr); + } else { + LOG(FATAL) << "Invalid logical expression kind: " << static_cast(expr->kind()); } auto &flattenOperands = static_cast(expr)->operands(); @@ -1118,8 +1140,7 @@ Expression::Kind ExpressionUtils::getNegatedLogicalExprKind(const Expression::Ki case Expression::Kind::kLogicalOr: return Expression::Kind::kLogicalAnd; case Expression::Kind::kLogicalXor: - LOG(FATAL) << "Unsupported logical expression kind: " << static_cast(kind); - break; + return Expression::Kind::kLogicalXor; default: LOG(FATAL) << "Invalid logical expression kind: " << static_cast(kind); break; diff --git a/src/graph/util/ExpressionUtils.h b/src/graph/util/ExpressionUtils.h index 29f3e96cc72..e762b4160ae 100644 --- a/src/graph/util/ExpressionUtils.h +++ b/src/graph/util/ExpressionUtils.h @@ -153,6 +153,11 @@ class ExpressionUtils { static void pullOrs(Expression* expr); static void pullOrsImpl(LogicalExpression* expr, std::vector& operands); + // For a logical XOR expression, extracts all non-logicalXorExpr from its operands and set them as + // the new operands + static void pullXors(Expression* expr); + static void pullXorsImpl(LogicalExpression* expr, std::vector& operands); + // Constructs a nested logical OR expression // Example: // [expr1, expr2, expr3] => ((expr1 OR expr2) OR expr3) diff --git a/src/graph/validator/GetSubgraphValidator.cpp b/src/graph/validator/GetSubgraphValidator.cpp index e2350c1d326..4e2989fe20d 100644 --- a/src/graph/validator/GetSubgraphValidator.cpp +++ b/src/graph/validator/GetSubgraphValidator.cpp @@ -33,6 +33,7 @@ Status GetSubgraphValidator::validateImpl() { // Validate in-bound edge types Status GetSubgraphValidator::validateInBound(InBoundClause* in) { auto& edgeTypes = subgraphCtx_->edgeTypes; + auto& edgeNames = subgraphCtx_->edgeNames; if (in != nullptr) { auto space = vctx_->whichSpace(); auto edges = in->edges(); @@ -42,8 +43,10 @@ Status GetSubgraphValidator::validateInBound(InBoundClause* in) { return Status::SemanticError("Get Subgraph not support rename edge name."); } - auto et = qctx_->schemaMng()->toEdgeType(space.id, *e->edge()); + std::string edgeName = *e->edge(); + auto et = qctx_->schemaMng()->toEdgeType(space.id, edgeName); NG_RETURN_IF_ERROR(et); + edgeNames.emplace(edgeName); auto v = -et.value(); edgeTypes.emplace(v); @@ -56,6 +59,7 @@ Status GetSubgraphValidator::validateInBound(InBoundClause* in) { // Validate out-bound edge types Status GetSubgraphValidator::validateOutBound(OutBoundClause* out) { auto& edgeTypes = subgraphCtx_->edgeTypes; + auto& edgeNames = subgraphCtx_->edgeNames; if (out != nullptr) { auto space = vctx_->whichSpace(); auto edges = out->edges(); @@ -64,10 +68,10 @@ Status GetSubgraphValidator::validateOutBound(OutBoundClause* out) { if (e->alias() != nullptr) { return Status::SemanticError("Get Subgraph not support rename edge name."); } - - auto et = qctx_->schemaMng()->toEdgeType(space.id, *e->edge()); + std::string edgeName = *e->edge(); + auto et = qctx_->schemaMng()->toEdgeType(space.id, edgeName); NG_RETURN_IF_ERROR(et); - + edgeNames.emplace(edgeName); edgeTypes.emplace(et.value()); } } @@ -79,8 +83,9 @@ Status GetSubgraphValidator::validateOutBound(OutBoundClause* out) { Status GetSubgraphValidator::validateBothInOutBound(BothInOutClause* out) { auto& edgeTypes = subgraphCtx_->edgeTypes; auto& biEdgeTypes = subgraphCtx_->biDirectEdgeTypes; + auto& edgeNames = subgraphCtx_->edgeNames; if (out != nullptr) { - auto space = vctx_->whichSpace(); + auto& space = vctx_->whichSpace(); auto edges = out->edges(); edgeTypes.reserve(edgeTypes.size() + edges.size() * 2); biEdgeTypes.reserve(edges.size() * 2); @@ -88,10 +93,10 @@ Status GetSubgraphValidator::validateBothInOutBound(BothInOutClause* out) { if (e->alias() != nullptr) { return Status::SemanticError("Get Subgraph not support rename edge name."); } - - auto et = qctx_->schemaMng()->toEdgeType(space.id, *e->edge()); + std::string edgeName = *e->edge(); + auto et = qctx_->schemaMng()->toEdgeType(space.id, edgeName); NG_RETURN_IF_ERROR(et); - + edgeNames.emplace(edgeName); auto v = et.value(); edgeTypes.emplace(v); edgeTypes.emplace(-v); @@ -146,12 +151,29 @@ Status GetSubgraphValidator::validateWhere(WhereClause* where) { NG_RETURN_IF_ERROR(deduceProps(filter, subgraphCtx_->exprProps)); + // check EdgeFilter's edge type is in the edge type list + // e.g. "like" is not in the edge list ["serve"] + // GET SUBGRAPH FROM 'xxx' both serve WHERE like.likeness < 90 YIELD vertices as v, edges as e + if (!subgraphCtx_->edgeNames.empty()) { + for (auto edgeProp : subgraphCtx_->exprProps.edgeProps()) { + auto filterEdgeName = qctx_->schemaMng()->toEdgeName(vctx_->whichSpace().id, edgeProp.first); + NG_RETURN_IF_ERROR(filterEdgeName); + if (subgraphCtx_->edgeNames.find(filterEdgeName.value()) == subgraphCtx_->edgeNames.end()) { + return Status::SemanticError( + fmt::format("Edge type \"{}\" in filter \"{}\" is not in the edge types [{}]", + filterEdgeName.value(), + filter->toString(), + folly::join(",", subgraphCtx_->edgeNames))); + } + } + } + auto condition = filter->clone(); if (ExpressionUtils::findAny(expr, {Expression::Kind::kDstProperty})) { auto visitor = ExtractFilterExprVisitor::makePushGetVertices(qctx_->objPool()); filter->accept(&visitor); if (!visitor.ok()) { - return Status::SemanticError("filter error"); + return Status::SemanticError("Push target vertices filter error: " + expr->toString()); } subgraphCtx_->edgeFilter = visitor.remainedExpr(); auto tagFilter = visitor.extractedExpr() ? visitor.extractedExpr() : filter; diff --git a/src/graph/validator/test/MockSchemaManager.cpp b/src/graph/validator/test/MockSchemaManager.cpp index 6236d73212e..3c5a88c50c3 100644 --- a/src/graph/validator/test/MockSchemaManager.cpp +++ b/src/graph/validator/test/MockSchemaManager.cpp @@ -99,7 +99,7 @@ StatusOr MockSchemaManager::toGraphSpaceID(folly::StringPiece spac if (findIt != spaceNameIds_.end()) { return findIt->second; } - return Status::Error("Space `%s' not found", spaceName.str().c_str()); + return Status::SpaceNotFound("Space `%s' not found", spaceName.str().c_str()); } StatusOr MockSchemaManager::toGraphSpaceName(GraphSpaceID space) { @@ -108,7 +108,7 @@ StatusOr MockSchemaManager::toGraphSpaceName(GraphSpaceID space) { return s.first; } } - return Status::Error("Space `%d' not found", space); + return Status::SpaceNotFound("Space `%d' not found", space); } StatusOr MockSchemaManager::toTagID(GraphSpaceID space, const folly::StringPiece tagName) { @@ -120,7 +120,7 @@ StatusOr MockSchemaManager::toTagID(GraphSpaceID space, const folly::Stri if (tagFindIt != tagNameIds_.end()) { return tagFindIt->second; } - return Status::Error("TagName `%s' not found", tagName.str().c_str()); + return Status::TagNotFound("TagName `%s' not found", tagName.str().c_str()); } StatusOr MockSchemaManager::toTagName(GraphSpaceID space, TagID tagId) { @@ -132,7 +132,7 @@ StatusOr MockSchemaManager::toTagName(GraphSpaceID space, TagID tag if (tagFindIt != tagIdNames_.end()) { return tagFindIt->second; } - return Status::Error("TagID `%d' not found", tagId); + return Status::TagNotFound("TagID `%d' not found", tagId); } StatusOr MockSchemaManager::toEdgeType(GraphSpaceID space, folly::StringPiece typeName) { @@ -144,7 +144,7 @@ StatusOr MockSchemaManager::toEdgeType(GraphSpaceID space, folly::Stri if (edgeFindIt != edgeNameIds_.end()) { return edgeFindIt->second; } - return Status::Error("EdgeName `%s' not found", typeName.str().c_str()); + return Status::EdgeNotFound("EdgeName `%s' not found", typeName.str().c_str()); } StatusOr MockSchemaManager::toEdgeName(GraphSpaceID space, EdgeType edgeType) { @@ -156,7 +156,7 @@ StatusOr MockSchemaManager::toEdgeName(GraphSpaceID space, EdgeType if (edgeFindIt != edgeIdNames_.end()) { return edgeFindIt->second; } - return Status::Error("EdgeType `%d' not found", edgeType); + return Status::EdgeNotFound("EdgeType `%d' not found", edgeType); } StatusOr> MockSchemaManager::getAllEdge(GraphSpaceID) { diff --git a/src/graph/visitor/PrunePropertiesVisitor.cpp b/src/graph/visitor/PrunePropertiesVisitor.cpp index 2bbefa74c1e..263171c1719 100644 --- a/src/graph/visitor/PrunePropertiesVisitor.cpp +++ b/src/graph/visitor/PrunePropertiesVisitor.cpp @@ -51,6 +51,13 @@ void PrunePropertiesVisitor::visitCurrent(Project *node) { auto *expr = col->expr(); status_ = extractPropsFromExpr(expr); if (!status_.ok()) { + // Project a not exit tag, should not break other columns + // e.g. Vertex tage {{"name", "string"}, {"age", "int64"}} + // Project "... RETURN v.name, v.xxx.yyy, v.player.age" + // v.xxx.yyy should not break v.player.age + if (status_.isTagNotFound()) { + continue; + } return; } } diff --git a/src/interface/common.thrift b/src/interface/common.thrift index 808ffaf769f..8b55a4e4030 100644 --- a/src/interface/common.thrift +++ b/src/interface/common.thrift @@ -95,7 +95,6 @@ enum NullType { BAD_DATA = 2, BAD_TYPE = 3, ERR_OVERFLOW = 4, - UNKNOWN_PROP = 5, DIV_BY_ZERO = 6, OUT_OF_RANGE = 7, } (cpp.enum_strict, cpp.type = "nebula::NullType") diff --git a/src/kvstore/CMakeLists.txt b/src/kvstore/CMakeLists.txt index 7f1e5afdfe3..ce5772e928d 100644 --- a/src/kvstore/CMakeLists.txt +++ b/src/kvstore/CMakeLists.txt @@ -5,14 +5,12 @@ nebula_add_library( kvstore_obj OBJECT Part.cpp - Listener.cpp RocksEngine.cpp PartManager.cpp NebulaStore.cpp RocksEngineConfig.cpp NebulaSnapshotManager.cpp RateLimiter.cpp - plugins/elasticsearch/ESListener.cpp ) nebula_add_library( @@ -21,6 +19,7 @@ nebula_add_library( ) nebula_add_subdirectory(raftex) +nebula_add_subdirectory(listener) nebula_add_subdirectory(wal) nebula_add_subdirectory(stats) nebula_add_subdirectory(test) diff --git a/src/kvstore/NebulaStore.cpp b/src/kvstore/NebulaStore.cpp index 566ff7714ab..d9a4a5a9166 100644 --- a/src/kvstore/NebulaStore.cpp +++ b/src/kvstore/NebulaStore.cpp @@ -17,7 +17,7 @@ #include "common/utils/NebulaKeyUtils.h" #include "kvstore/NebulaSnapshotManager.h" #include "kvstore/RocksEngine.h" -#include "kvstore/plugins/elasticsearch/ESListener.h" +#include "kvstore/listener/elasticsearch/ESListener.h" DEFINE_string(engine_type, "rocksdb", "rocksdb, memory..."); DEFINE_int32(custom_filter_interval_secs, @@ -568,13 +568,13 @@ void NebulaStore::removePart(GraphSpaceID spaceId, PartitionID partId, bool need void NebulaStore::addListenerSpace(GraphSpaceID spaceId, meta::cpp2::ListenerType type) { UNUSED(type); folly::RWSpinLock::WriteHolder wh(&lock_); - // listener don't need engine for now if (this->spaceListeners_.find(spaceId) != this->spaceListeners_.end()) { LOG(INFO) << "Listener space " << spaceId << " has existed!"; - return; + } else { + LOG(INFO) << "Create listener space " << spaceId; + this->spaceListeners_[spaceId] = std::make_unique(); } - LOG(INFO) << "Create listener space " << spaceId; - this->spaceListeners_[spaceId] = std::make_unique(); + // Perform extra initialization of given type of listener here } void NebulaStore::removeListenerSpace(GraphSpaceID spaceId, meta::cpp2::ListenerType type) { diff --git a/src/kvstore/NebulaStore.h b/src/kvstore/NebulaStore.h index 276a4751d38..17921afd396 100644 --- a/src/kvstore/NebulaStore.h +++ b/src/kvstore/NebulaStore.h @@ -17,9 +17,9 @@ #include "kvstore/DiskManager.h" #include "kvstore/KVEngine.h" #include "kvstore/KVStore.h" -#include "kvstore/Listener.h" #include "kvstore/Part.h" #include "kvstore/PartManager.h" +#include "kvstore/listener/Listener.h" #include "kvstore/raftex/RaftexService.h" #include "kvstore/raftex/SnapshotManager.h" diff --git a/src/kvstore/RocksEngine.cpp b/src/kvstore/RocksEngine.cpp index 408fc3dbc40..eadacf20092 100644 --- a/src/kvstore/RocksEngine.cpp +++ b/src/kvstore/RocksEngine.cpp @@ -92,7 +92,17 @@ RocksEngine::RocksEngine(GraphSpaceID spaceId, CHECK(status.ok()) << status.ToString(); } db_.reset(db); - extractorLen_ = sizeof(PartitionID) + vIdLen; + std::string factoryName = options.table_factory->Name(); + if (factoryName == rocksdb::TableFactory::kBlockBasedTableName()) { + extractorLen_ = sizeof(PartitionID) + vIdLen; + } else if (factoryName == rocksdb::TableFactory::kPlainTableName()) { + // PlainTable only support prefix-based seek, which means if the prefix is not inserted into + // rocksdb, we can't read them from "prefix" api anymore. For simplicity, we just set the length + // of prefix extractor to the minimum length we used in "prefix" api, which is 4 when we seek by + // tagPrefix(partId) or edgePrefix(partId). + isPlainTable_ = true; + extractorLen_ = sizeof(PartitionID); + } partsNum_ = allParts().size(); LOG(INFO) << "open rocksdb on " << path; @@ -175,7 +185,11 @@ nebula::cpp2::ErrorCode RocksEngine::range(const std::string& start, const std::string& end, std::unique_ptr* storageIter) { rocksdb::ReadOptions options; - options.total_order_seek = FLAGS_enable_rocksdb_prefix_filtering; + if (!isPlainTable_) { + options.total_order_seek = FLAGS_enable_rocksdb_prefix_filtering; + } else { + options.prefix_same_as_start = true; + } rocksdb::Iterator* iter = db_->NewIterator(options); if (iter) { iter->Seek(rocksdb::Slice(start)); @@ -232,8 +246,11 @@ nebula::cpp2::ErrorCode RocksEngine::rangeWithPrefix(const std::string& start, const std::string& prefix, std::unique_ptr* storageIter) { rocksdb::ReadOptions options; - // prefix_same_as_start is false by default - options.total_order_seek = FLAGS_enable_rocksdb_prefix_filtering; + if (!isPlainTable_) { + options.total_order_seek = FLAGS_enable_rocksdb_prefix_filtering; + } else { + options.prefix_same_as_start = true; + } rocksdb::Iterator* iter = db_->NewIterator(options); if (iter) { iter->Seek(rocksdb::Slice(start)); diff --git a/src/kvstore/RocksEngine.h b/src/kvstore/RocksEngine.h index 17569163c8e..caaaefbcb0a 100644 --- a/src/kvstore/RocksEngine.h +++ b/src/kvstore/RocksEngine.h @@ -552,6 +552,7 @@ class RocksEngine : public KVEngine { std::unique_ptr backupDb_{nullptr}; int32_t partsNum_ = -1; size_t extractorLen_; + bool isPlainTable_{false}; }; } // namespace kvstore diff --git a/src/kvstore/RocksEngineConfig.cpp b/src/kvstore/RocksEngineConfig.cpp index 5dbcc40532d..50e3090b5cb 100644 --- a/src/kvstore/RocksEngineConfig.cpp +++ b/src/kvstore/RocksEngineConfig.cpp @@ -292,7 +292,6 @@ rocksdb::Status initRocksdbOptions(rocksdb::Options& baseOpts, baseOpts.rate_limiter = rate_limiter; } - size_t prefixLength = sizeof(PartitionID) + vidLen; if (FLAGS_rocksdb_table_format == "BlockBasedTable") { // BlockBasedTableOptions std::unordered_map bbtOptsMap; @@ -330,6 +329,7 @@ rocksdb::Status initRocksdbOptions(rocksdb::Options& baseOpts, baseOpts.compaction_style == rocksdb::CompactionStyle::kCompactionStyleLevel; } if (FLAGS_enable_rocksdb_prefix_filtering) { + size_t prefixLength = sizeof(PartitionID) + vidLen; baseOpts.prefix_extractor.reset(rocksdb::NewCappedPrefixTransform(prefixLength)); } bbtOpts.whole_key_filtering = FLAGS_enable_rocksdb_whole_key_filtering; @@ -346,6 +346,11 @@ rocksdb::Status initRocksdbOptions(rocksdb::Options& baseOpts, if (!FLAGS_enable_rocksdb_prefix_filtering) { return rocksdb::Status::InvalidArgument("PlainTable should use prefix bloom filter"); } + // PlainTable only support prefix-based seek, which means if the prefix is not inserted into + // rocksdb, we can't read them from "prefix" api anymore. For simplicity, we just set the length + // of prefix extractor to the minimum length we used in "prefix" api, which is 4 when we seek by + // tagPrefix(partId) or edgePrefix(partId). + size_t prefixLength = sizeof(PartitionID); baseOpts.prefix_extractor.reset(rocksdb::NewCappedPrefixTransform(prefixLength)); baseOpts.table_factory.reset(rocksdb::NewPlainTableFactory()); baseOpts.create_if_missing = true; diff --git a/src/kvstore/listener/CMakeLists.txt b/src/kvstore/listener/CMakeLists.txt new file mode 100644 index 00000000000..03273c5f2ca --- /dev/null +++ b/src/kvstore/listener/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2022 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License. + +nebula_add_library( + listener_obj OBJECT + Listener.cpp + elasticsearch/ESListener.cpp +) + +nebula_add_subdirectory(test) diff --git a/src/kvstore/Listener.cpp b/src/kvstore/listener/Listener.cpp similarity index 99% rename from src/kvstore/Listener.cpp rename to src/kvstore/listener/Listener.cpp index 2bccddd26dd..f50d5ee11c8 100644 --- a/src/kvstore/Listener.cpp +++ b/src/kvstore/listener/Listener.cpp @@ -3,7 +3,7 @@ * This source code is licensed under Apache 2.0 License. */ -#include "kvstore/Listener.h" +#include "kvstore/listener/Listener.h" #include "codec/RowReaderWrapper.h" #include "common/time/WallClock.h" @@ -155,8 +155,6 @@ void Listener::doApply() { }); } - - void Listener::resetListener() { std::lock_guard g(raftLock_); reset(); diff --git a/src/kvstore/Listener.h b/src/kvstore/listener/Listener.h similarity index 98% rename from src/kvstore/Listener.h rename to src/kvstore/listener/Listener.h index 3391811b02f..9df8672b7f1 100644 --- a/src/kvstore/Listener.h +++ b/src/kvstore/listener/Listener.h @@ -3,8 +3,8 @@ * This source code is licensed under Apache 2.0 License. */ -#ifndef KVSTORE_LISTENER_H_ -#define KVSTORE_LISTENER_H_ +#ifndef KVSTORE_LISTENER_LISTENER_H_ +#define KVSTORE_LISTENER_LISTENER_H_ #include "common/base/Base.h" #include "common/meta/SchemaManager.h" @@ -274,10 +274,9 @@ class Listener : public raftex::RaftPart { protected: LogID leaderCommitId_ = 0; LogID lastApplyLogId_ = 0; - int64_t lastApplyTime_ = 0; std::set peers_; }; } // namespace kvstore } // namespace nebula -#endif // KVSTORE_LISTENER_H_ +#endif diff --git a/src/kvstore/plugins/elasticsearch/ESListener.cpp b/src/kvstore/listener/elasticsearch/ESListener.cpp similarity index 98% rename from src/kvstore/plugins/elasticsearch/ESListener.cpp rename to src/kvstore/listener/elasticsearch/ESListener.cpp index 05121ea196b..58939e4cfcb 100644 --- a/src/kvstore/plugins/elasticsearch/ESListener.cpp +++ b/src/kvstore/listener/elasticsearch/ESListener.cpp @@ -3,7 +3,7 @@ * This source code is licensed under Apache 2.0 License. */ -#include "kvstore/plugins/elasticsearch/ESListener.h" +#include "kvstore/listener/elasticsearch/ESListener.h" #include "common/plugin/fulltext/elasticsearch/ESStorageAdapter.h" #include "common/utils/NebulaKeyUtils.h" @@ -321,7 +321,6 @@ void ESListener::processLogs() { lastApplyLogId_ = lastApplyId; persist(committedLogId_, term_, lastApplyLogId_); VLOG(2) << idStr_ << "Listener succeeded apply log to " << lastApplyLogId_; - lastApplyTime_ = time::WallClock::fastNowInMilliSec(); } } @@ -351,7 +350,6 @@ std::tuple ESListener::commitSnapshot leaderCommitId_ = committedLogId; lastApplyLogId_ = committedLogId; persist(committedLogId, committedLogTerm, lastApplyLogId_); - lastApplyTime_ = time::WallClock::fastNowInMilliSec(); LOG(INFO) << folly::sformat( "Commit snapshot to : committedLogId={}," "committedLogTerm={}, lastApplyLogId_={}", diff --git a/src/kvstore/plugins/elasticsearch/ESListener.h b/src/kvstore/listener/elasticsearch/ESListener.h similarity index 97% rename from src/kvstore/plugins/elasticsearch/ESListener.h rename to src/kvstore/listener/elasticsearch/ESListener.h index 19c9fd8c73f..0e079735926 100644 --- a/src/kvstore/plugins/elasticsearch/ESListener.h +++ b/src/kvstore/listener/elasticsearch/ESListener.h @@ -3,12 +3,12 @@ * This source code is licensed under Apache 2.0 License. */ -#ifndef KVSTORE_PLUGINS_ES_LISTENER_H_ -#define KVSTORE_PLUGINS_ES_LISTENER_H_ +#ifndef KVSTORE_LISTENER_ES_LISTENER_H_ +#define KVSTORE_LISTENER_ES_LISTENER_H_ #include "codec/RowReaderWrapper.h" #include "common/plugin/fulltext/FTStorageAdapter.h" -#include "kvstore/Listener.h" +#include "kvstore/listener/Listener.h" namespace nebula { namespace kvstore { @@ -171,4 +171,4 @@ class ESListener : public Listener { } // namespace kvstore } // namespace nebula -#endif // KVSTORE_PLUGINS_ES_LISTENER_H_ +#endif diff --git a/src/kvstore/listener/test/CMakeLists.txt b/src/kvstore/listener/test/CMakeLists.txt new file mode 100644 index 00000000000..b1e87a75ab2 --- /dev/null +++ b/src/kvstore/listener/test/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (c) 2022 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License. + +set(LISTENER_TEST_LIBS + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ +) + +nebula_add_test( + NAME + nebula_listener_test + SOURCES + NebulaListenerTest.cpp + OBJECTS + ${LISTENER_TEST_LIBS} + LIBRARIES + ${THRIFT_LIBRARIES} + ${ROCKSDB_LIBRARIES} + ${PROXYGEN_LIBRARIES} + wangle + gtest +) diff --git a/src/kvstore/test/NebulaListenerTest.cpp b/src/kvstore/listener/test/NebulaListenerTest.cpp similarity index 99% rename from src/kvstore/test/NebulaListenerTest.cpp rename to src/kvstore/listener/test/NebulaListenerTest.cpp index 816c2093e80..3d454cfc23f 100644 --- a/src/kvstore/test/NebulaListenerTest.cpp +++ b/src/kvstore/listener/test/NebulaListenerTest.cpp @@ -76,7 +76,6 @@ class DummyListener : public Listener { leaderCommitId_ = committedLogId; lastApplyLogId_ = committedLogId; persist(committedLogId, committedLogTerm, lastApplyLogId_); - lastApplyTime_ = time::WallClock::fastNowInMilliSec(); LOG(INFO) << folly::sformat( "Commit snapshot to : committedLogId={}," "committedLogTerm={}, lastApplyLogId_={}", @@ -179,7 +178,6 @@ class DummyListener : public Listener { lastApplyLogId_ = lastApplyId; persist(committedLogId_, term_, lastApplyLogId_); VLOG(2) << idStr_ << "Listener succeeded apply log to " << lastApplyLogId_; - lastApplyTime_ = time::WallClock::fastNowInMilliSec(); } } diff --git a/src/kvstore/plugins/CMakeLists.txt b/src/kvstore/plugins/CMakeLists.txt deleted file mode 100644 index 03f9351dbfc..00000000000 --- a/src/kvstore/plugins/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2022 vesoft inc. All rights reserved. -# -# This source code is licensed under Apache 2.0 License. - -nebula_add_subdirectory(elasticsearch) diff --git a/src/kvstore/test/CMakeLists.txt b/src/kvstore/test/CMakeLists.txt index 32ab49bbbf7..2c2e126ef48 100644 --- a/src/kvstore/test/CMakeLists.txt +++ b/src/kvstore/test/CMakeLists.txt @@ -5,6 +5,7 @@ set(KVSTORE_TEST_LIBS $ $ + $ $ $ $ @@ -107,21 +108,6 @@ nebula_add_test( gtest ) -nebula_add_test( - NAME - nebula_listener_test - SOURCES - NebulaListenerTest.cpp - OBJECTS - ${KVSTORE_TEST_LIBS} - LIBRARIES - ${THRIFT_LIBRARIES} - ${ROCKSDB_LIBRARIES} - ${PROXYGEN_LIBRARIES} - wangle - gtest -) - nebula_add_test( NAME rocks_engine_config_test diff --git a/src/kvstore/test/RocksEngineTest.cpp b/src/kvstore/test/RocksEngineTest.cpp index a5eb967157d..f1e22cd244b 100644 --- a/src/kvstore/test/RocksEngineTest.cpp +++ b/src/kvstore/test/RocksEngineTest.cpp @@ -19,16 +19,20 @@ namespace kvstore { const int32_t kDefaultVIdLen = 8; -class RocksEngineTest : public ::testing::TestWithParam> { +class RocksEngineTest : public ::testing::TestWithParam> { public: void SetUp() override { auto param = GetParam(); FLAGS_enable_rocksdb_prefix_filtering = std::get<0>(param); FLAGS_enable_rocksdb_whole_key_filtering = std::get<1>(param); FLAGS_rocksdb_table_format = std::get<2>(param); + flush_ = std::get<3>(param); } void TearDown() override {} + + protected: + bool flush_; }; TEST_P(RocksEngineTest, SimpleTest) { @@ -36,6 +40,9 @@ TEST_P(RocksEngineTest, SimpleTest) { auto engine = std::make_unique(0, kDefaultVIdLen, rootPath.path()); EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->put("key", "val")); std::string val; + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->get("key", &val)); EXPECT_EQ("val", val); } @@ -45,22 +52,26 @@ TEST_P(RocksEngineTest, RangeTest) { auto engine = std::make_unique(0, kDefaultVIdLen, rootPath.path()); std::vector data; for (int32_t i = 10; i < 20; i++) { - data.emplace_back(std::string(reinterpret_cast(&i), sizeof(int32_t)), + data.emplace_back("key_" + std::string(reinterpret_cast(&i), sizeof(int32_t)), folly::stringPrintf("val_%d", i)); } EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->multiPut(std::move(data))); + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } auto checkRange = [&](int32_t start, int32_t end, int32_t expectedFrom, int32_t expectedTotal) { VLOG(1) << "start " << start << ", end " << end << ", expectedFrom " << expectedFrom << ", expectedTotal " << expectedTotal; - std::string s(reinterpret_cast(&start), sizeof(int32_t)); - std::string e(reinterpret_cast(&end), sizeof(int32_t)); + std::string s = "key_" + std::string(reinterpret_cast(&start), sizeof(int32_t)); + std::string e = "key_" + std::string(reinterpret_cast(&end), sizeof(int32_t)); std::unique_ptr iter; EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->range(s, e, &iter)); int num = 0; while (iter->valid()) { num++; - auto key = *reinterpret_cast(iter->key().data()); + // remove the prefix "key_" + auto key = *reinterpret_cast(iter->key().subpiece(4).data()); auto val = iter->val(); EXPECT_EQ(expectedFrom, key); EXPECT_EQ(folly::stringPrintf("val_%d", expectedFrom), val); @@ -83,15 +94,18 @@ TEST_P(RocksEngineTest, PrefixTest) { LOG(INFO) << "Write data in batch and scan them..."; std::vector data; for (int32_t i = 0; i < 10; i++) { - data.emplace_back(folly::stringPrintf("a_%d", i), folly::stringPrintf("val_%d", i)); + data.emplace_back(folly::stringPrintf("key_a_%d", i), folly::stringPrintf("val_%d", i)); } for (int32_t i = 10; i < 15; i++) { - data.emplace_back(folly::stringPrintf("b_%d", i), folly::stringPrintf("val_%d", i)); + data.emplace_back(folly::stringPrintf("key_b_%d", i), folly::stringPrintf("val_%d", i)); } for (int32_t i = 20; i < 40; i++) { - data.emplace_back(folly::stringPrintf("c_%d", i), folly::stringPrintf("val_%d", i)); + data.emplace_back(folly::stringPrintf("key_c_%d", i), folly::stringPrintf("val_%d", i)); } EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->multiPut(std::move(data))); + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } auto checkPrefix = [&](const std::string& prefix, int32_t expectedFrom, int32_t expectedTotal) { VLOG(1) << "prefix " << prefix << ", expectedFrom " << expectedFrom << ", expectedTotal " @@ -111,9 +125,9 @@ TEST_P(RocksEngineTest, PrefixTest) { } EXPECT_EQ(expectedTotal, num); }; - checkPrefix("a", 0, 10); - checkPrefix("b", 10, 5); - checkPrefix("c", 20, 20); + checkPrefix("key_a", 0, 10); + checkPrefix("key_b", 10, 5); + checkPrefix("key_c", 20, 20); } TEST_P(RocksEngineTest, RemoveTest) { @@ -147,6 +161,9 @@ TEST_P(RocksEngineTest, RemoveRangeTest) { engine->removeRange(std::string(reinterpret_cast(&s), sizeof(int32_t)), std::string(reinterpret_cast(&e), sizeof(int32_t)))); } + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } { int32_t s = 0, e = 100; std::unique_ptr iter; @@ -218,6 +235,9 @@ TEST_P(RocksEngineTest, IngestTest) { auto engine = std::make_unique(0, kDefaultVIdLen, rootPath.path()); std::vector files = {file}; EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->ingest(files)); + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } std::string result; EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->get("key", &result)); @@ -264,6 +284,9 @@ TEST_P(RocksEngineTest, BackupRestoreTable) { fs::TempDir restoreRootPath("/tmp/rocksdb_engine_restoretable.XXXXXX"); auto restore_engine = std::make_unique(0, kDefaultVIdLen, restoreRootPath.path()); EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, restore_engine->ingest(sst_files)); + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } std::unique_ptr iter; EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, restore_engine->prefix(partPrefix, &iter)); @@ -465,6 +488,9 @@ TEST_P(RocksEngineTest, PrefixBloomTest) { data.emplace_back(NebulaKeyUtils::systemCommitKey(1), "123"); data.emplace_back(NebulaKeyUtils::systemCommitKey(2), "123"); EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->multiPut(std::move(data))); + if (flush_) { + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, engine->flush()); + } { // vertexPrefix(partId) will not be included @@ -531,15 +557,21 @@ TEST_P(RocksEngineTest, PrefixBloomTest) { } } -INSTANTIATE_TEST_SUITE_P(EnablePrefixExtractor_EnableWholeKeyFilter_TableFormat, +INSTANTIATE_TEST_SUITE_P(EnablePrefixExtractor_EnableWholeKeyFilter_TableFormat_FlushOrNot, RocksEngineTest, - ::testing::Values(std::make_tuple(false, false, "BlockBasedTable"), - std::make_tuple(false, true, "BlockBasedTable"), - std::make_tuple(true, false, "BlockBasedTable"), - std::make_tuple(true, true, "BlockBasedTable"), + ::testing::Values(std::make_tuple(false, false, "BlockBasedTable", true), + std::make_tuple(false, false, "BlockBasedTable", false), + std::make_tuple(false, true, "BlockBasedTable", true), + std::make_tuple(false, true, "BlockBasedTable", false), + std::make_tuple(true, false, "BlockBasedTable", true), + std::make_tuple(true, false, "BlockBasedTable", false), + std::make_tuple(true, true, "BlockBasedTable", true), + std::make_tuple(true, true, "BlockBasedTable", false), // PlainTable will always enable prefix extractor - std::make_tuple(true, false, "PlainTable"), - std::make_tuple(true, true, "PlainTable"))); + std::make_tuple(true, false, "PlainTable", true), + std::make_tuple(true, false, "PlainTable", false), + std::make_tuple(true, true, "PlainTable", true), + std::make_tuple(true, true, "PlainTable", false))); TEST(PlainTableTest, BackupRestoreWithoutData) { fs::TempDir dataPath("/tmp/rocks_engine_test_data_path.XXXXXX"); @@ -580,19 +612,33 @@ TEST(PlainTableTest, BackupRestoreWithData) { PartitionID partId = 1; auto checkData = [&] { - std::string prefix = NebulaKeyUtils::tagPrefix(kDefaultVIdLen, partId, "vertex"); - std::unique_ptr iter; - auto code = engine->prefix(prefix, &iter); - EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, code); - int32_t num = 0; - while (iter->valid()) { - num++; - iter->next(); + { + std::string prefix = NebulaKeyUtils::tagPrefix(kDefaultVIdLen, partId, "vertex"); + std::unique_ptr iter; + auto code = engine->prefix(prefix, &iter); + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, code); + int32_t num = 0; + while (iter->valid()) { + num++; + iter->next(); + } + EXPECT_EQ(num, 10); + } + { + std::string prefix = NebulaKeyUtils::tagPrefix(partId); + std::unique_ptr iter; + auto code = engine->prefix(prefix, &iter); + EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, code); + int32_t num = 0; + while (iter->valid()) { + num++; + iter->next(); + } + EXPECT_EQ(num, 10); } - EXPECT_EQ(num, 10); std::string value; - code = engine->get(NebulaKeyUtils::systemCommitKey(partId), &value); + auto code = engine->get(NebulaKeyUtils::systemCommitKey(partId), &value); EXPECT_EQ(nebula::cpp2::ErrorCode::SUCCEEDED, code); EXPECT_EQ("123", value); }; diff --git a/src/meta/CMakeLists.txt b/src/meta/CMakeLists.txt index 0c31c9404c2..357fa0db736 100644 --- a/src/meta/CMakeLists.txt +++ b/src/meta/CMakeLists.txt @@ -130,6 +130,7 @@ set(meta_test_deps $ $ $ + $ $ $ $ diff --git a/src/meta/test/MetaClientTest.cpp b/src/meta/test/MetaClientTest.cpp index f79c47b9df7..affb25e7a26 100644 --- a/src/meta/test/MetaClientTest.cpp +++ b/src/meta/test/MetaClientTest.cpp @@ -725,7 +725,7 @@ TEST(MetaClientTest, TagIndexTest) { client->createTagIndex(space, "tag_not_exist_index", "tag_not_exist", std::move(fields)) .get(); ASSERT_FALSE(result.ok()); - ASSERT_EQ(Status::Error("not existed!"), result.status()); + ASSERT_EQ(Status::TagNotFound("not existed!"), result.status()); } { std::vector fields; diff --git a/src/storage/exec/IndexEdgeScanNode.cpp b/src/storage/exec/IndexEdgeScanNode.cpp index 9eb9fb26cb2..d4dcfd67ecd 100644 --- a/src/storage/exec/IndexEdgeScanNode.cpp +++ b/src/storage/exec/IndexEdgeScanNode.cpp @@ -122,7 +122,7 @@ Map IndexEdgeScanNode::decodeFromBase(const std::string& key case QueryUtils::ReturnColType::kOther: { auto field = edge_.back()->field(col); if (field == nullptr) { - values[col] = Value::kNullUnknownProp; + values[col] = Value::kNullValue; } else { auto retVal = QueryUtils::readValue(reader.get(), col, field); if (!retVal.ok()) { diff --git a/src/storage/exec/IndexVertexScanNode.cpp b/src/storage/exec/IndexVertexScanNode.cpp index 4dcfd01075c..fd2eed2ae0c 100644 --- a/src/storage/exec/IndexVertexScanNode.cpp +++ b/src/storage/exec/IndexVertexScanNode.cpp @@ -99,7 +99,7 @@ Map IndexVertexScanNode::decodeFromBase(const std::string& k case QueryUtils::ReturnColType::kOther: { auto field = tag_.back()->field(col); if (field == nullptr) { - values[col] = Value::kNullUnknownProp; + values[col] = Value::kNullValue; } else { auto retVal = QueryUtils::readValue(reader.get(), col, field); if (!retVal.ok()) { diff --git a/src/storage/exec/QueryUtils.h b/src/storage/exec/QueryUtils.h index 4a3c1499727..1fe1103cf17 100644 --- a/src/storage/exec/QueryUtils.h +++ b/src/storage/exec/QueryUtils.h @@ -79,7 +79,7 @@ class QueryUtils final { // read null value auto nullType = value.getNull(); - if (nullType == NullType::UNKNOWN_PROP) { + if (nullType == NullType::__NULL__) { VLOG(1) << "Fail to read prop " << propName; if (!field) { return value; diff --git a/src/storage/test/CMakeLists.txt b/src/storage/test/CMakeLists.txt index 39bc5dfd5cb..339fea49a7a 100644 --- a/src/storage/test/CMakeLists.txt +++ b/src/storage/test/CMakeLists.txt @@ -18,6 +18,7 @@ set(storage_test_deps $ $ $ + $ $ $ $ diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index d6c2d226143..cd300852a8a 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -17,6 +17,7 @@ set(tools_test_deps $ $ $ + $ $ $ $ diff --git a/src/tools/db-upgrade/DbUpgrader.cpp b/src/tools/db-upgrade/DbUpgrader.cpp index c0834d87339..822f9cc7899 100644 --- a/src/tools/db-upgrade/DbUpgrader.cpp +++ b/src/tools/db-upgrade/DbUpgrader.cpp @@ -867,7 +867,7 @@ std::string UpgraderSpace::encodeRowVal(const RowReader* reader, LOG(ERROR) << "Write rowWriterV2 failed"; return ""; } - } else if (nullType != NullType::UNKNOWN_PROP) { + } else if (nullType != NullType::__NULL__) { // nullType == NullType::kNullUnknownProp, indicates that the field is // only in the latest schema, maybe use default value or null value. LOG(ERROR) << "Data is illegal in " << name << " field"; diff --git a/tests/Makefile b/tests/Makefile index 0d4119ce3a3..46d703e9310 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -142,3 +142,6 @@ clean: kill: ps -ef | grep -P '\sbin/nebula-' | grep "$$(whoami)" | sed 's/\s\s*/ /g' | cut -f2 -d' ' | xargs kill -9 + +ps: + @ps -ef | grep -P '\sbin/nebula-' | grep "$$(whoami)" diff --git a/tests/common/nebula_test_suite.py b/tests/common/nebula_test_suite.py index 83b746704b3..efc0c1f128c 100644 --- a/tests/common/nebula_test_suite.py +++ b/tests/common/nebula_test_suite.py @@ -34,8 +34,8 @@ T_NULL_BAD_DATA.set_nVal(CommonTtypes.NullType.BAD_DATA) T_NULL_BAD_TYPE = CommonTtypes.Value() T_NULL_BAD_TYPE.set_nVal(CommonTtypes.NullType.BAD_TYPE) -T_NULL_UNKNOWN_PROP = CommonTtypes.Value() -T_NULL_UNKNOWN_PROP.set_nVal(CommonTtypes.NullType.UNKNOWN_PROP) +T_NULL___NULL__ = CommonTtypes.Value() +T_NULL___NULL__.set_nVal(CommonTtypes.NullType.__NULL__) T_NULL_UNKNOWN_DIV_BY_ZERO = CommonTtypes.Value() T_NULL_UNKNOWN_DIV_BY_ZERO.set_nVal(CommonTtypes.NullType.DIV_BY_ZERO) diff --git a/tests/tck/features/bugfix/ArgumentPlanNodeDep.feature b/tests/tck/features/bugfix/ArgumentPlanNodeDep.feature new file mode 100644 index 00000000000..511a44f6878 --- /dev/null +++ b/tests/tck/features/bugfix/ArgumentPlanNodeDep.feature @@ -0,0 +1,28 @@ +Feature: Fix Argument plan node dependency + + Background: + Given a graph with space named "nba" + + Scenario: fix argument plan node dependency in issue 4938 + When profiling query: + """ + MATCH (a:player) + WHERE id(a)=='Tim Duncan' + MATCH (a)-[:like]-(b) + RETURN count(*) AS cnt + """ + Then the result should be, in any order: + | cnt | + | 12 | + And the execution plan should be: + | id | name | dependencies | operator info | + | 11 | Aggregate | 10 | | + | 10 | BiInnerJoin | 8,4 | | + | 8 | AppendVertices | 7 | | + | 7 | Dedup | 6 | | + | 6 | PassThrough | 5 | | + | 5 | Start | | | + | 4 | Project | 3 | | + | 3 | AppendVertices | 2 | | + | 2 | Traverse | 1 | | + | 1 | Argument | | | diff --git a/tests/tck/features/expression/Attribute.feature b/tests/tck/features/expression/Attribute.feature index c471c3554c4..bfff234892f 100644 --- a/tests/tck/features/expression/Attribute.feature +++ b/tests/tck/features/expression/Attribute.feature @@ -61,8 +61,8 @@ Feature: Attribute RETURN {k1 : 1, k2: true}.K1 AS k """ Then the result should be, in any order: - | k | - | UNKNOWN_PROP | + | k | + | __NULL__ | When executing query: """ MATCH (v) WHERE id(v) == 'Tim Duncan' RETURN v.player.name @@ -101,28 +101,28 @@ Feature: Attribute """ Then the result should be, in any order: | not_exists_attr | - | UNKNOWN_PROP | + | __NULL__ | When executing query: """ RETURN time("02:59:40").not_exists_attr AS not_exists_attr """ Then the result should be, in any order: | not_exists_attr | - | UNKNOWN_PROP | + | __NULL__ | When executing query: """ RETURN datetime("2021-07-19T02:59:40").not_exists_attr AS not_exists_attr """ Then the result should be, in any order: | not_exists_attr | - | UNKNOWN_PROP | + | __NULL__ | When executing query: """ RETURN {k1 : 1, k2: true}.not_exists_attr AS not_exists_attr """ Then the result should be, in any order: | not_exists_attr | - | UNKNOWN_PROP | + | __NULL__ | When executing query: """ MATCH (v) WHERE id(v) == 'Tim Duncan' RETURN v.player.not_exists_attr diff --git a/tests/tck/features/expression/LogicalExpression.feature b/tests/tck/features/expression/LogicalExpression.feature new file mode 100644 index 00000000000..f299cb4fe74 --- /dev/null +++ b/tests/tck/features/expression/LogicalExpression.feature @@ -0,0 +1,21 @@ +# Copyright (c) 2020 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License. +Feature: Logical Expression + + Scenario: xor crash bug fix 1 + Given a graph with space named "nba" + When executing query: + """ + match (v0:player)-[e:serve]->(v1) where not ((e.start_year == 1997 xor e.end_year != 2016) or (e.start_year > 1000 and e.end_year < 3000)) return count(*) + """ + Then the result should be, in any order: + | count(*) | + | 0 | + When executing query: + """ + match (v0:player)-[e:serve]->(v1) where not ((e.start_year == 1997 xor e.end_year != 2016) and (e.start_year > 1000 and e.end_year < 3000)) return count(*) + """ + Then the result should be, in any order: + | count(*) | + | 140 | diff --git a/tests/tck/features/match/MultiLineMultiQueryParts.feature b/tests/tck/features/match/MultiLineMultiQueryParts.feature index 1b4c9e1634b..fafc5ae4d87 100644 --- a/tests/tck/features/match/MultiLineMultiQueryParts.feature +++ b/tests/tck/features/match/MultiLineMultiQueryParts.feature @@ -84,6 +84,18 @@ Feature: Multi Line Multi Query Parts | "Tim Duncan" | "Boris Diaw" | "Spurs" | | "Tim Duncan" | "Boris Diaw" | "Suns" | | "Tim Duncan" | "Boris Diaw" | "Tim Duncan" | + When executing query: + """ + MATCH (v:player{name:"Tim Duncan"})-[:like*1..3]->(n) + WITH DISTINCT v, n + MATCH (v)-[:serve]->(nn) return id(v) AS vid, id(nn) AS nnid + """ + Then the result should be, in any order: + | vid | nnid | + | "Tim Duncan" | "Spurs" | + | "Tim Duncan" | "Spurs" | + | "Tim Duncan" | "Spurs" | + | "Tim Duncan" | "Spurs" | When executing query: """ MATCH (m)-[]-(n),(n) WHERE id(m)=="Tim Duncan" and id(n)=="Tony Parker" diff --git a/tests/tck/features/match/With.feature b/tests/tck/features/match/With.feature index 8cf68f1edd1..9f76a59e9b7 100644 --- a/tests/tck/features/match/With.feature +++ b/tests/tck/features/match/With.feature @@ -94,8 +94,8 @@ Feature: With clause RETURN x.c """ Then the result should be, in any order: - | x.c | - | UNKNOWN_PROP | + | x.c | + | __NULL__ | Scenario: match with return When executing query: diff --git a/tests/tck/features/mutate/ClearSpace.feature b/tests/tck/features/mutate/ClearSpace.feature index 5942c7ded04..e24ae3a1513 100644 --- a/tests/tck/features/mutate/ClearSpace.feature +++ b/tests/tck/features/mutate/ClearSpace.feature @@ -31,7 +31,7 @@ Feature: Clear space test """ CLEAR SPACE clear_space_0; """ - Then a ExecutionError should be raised at runtime: Space not existed! + Then a ExecutionError should be raised at runtime: SpaceNotFound: Space not existed! And drop the used space Scenario: Clear space function test diff --git a/tests/tck/features/optimizer/PrunePropertiesRule.feature b/tests/tck/features/optimizer/PrunePropertiesRule.feature index 87810327a73..4fdc4c245c5 100644 --- a/tests/tck/features/optimizer/PrunePropertiesRule.feature +++ b/tests/tck/features/optimizer/PrunePropertiesRule.feature @@ -183,7 +183,8 @@ Feature: Prune Properties rule | 23 | Project | 8 | | | 8 | AppendVertices | 7 | { "props": "[{\"tagId\":9,\"props\":[\"name\"]}, {\"tagId\":10,\"props\":[\"name\"]}]" } | | 7 | Traverse | 6 | { "vertexProps": "[{\"tagId\":9,\"props\":[\"name\"]}]", "edgeProps": "[{\"type\": -5, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"type\": 5, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": -3}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 3}, {\"type\": -4, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 4}]" } | - | 6 | Argument | | | + | 6 | Argument | 0 | | + | 0 | Start | | | When profiling query: """ MATCH (m)-[]-(n), (n)-[]-(l), (l)-[]-(h) WHERE id(m)=="Tim Duncan" @@ -218,11 +219,11 @@ Feature: Prune Properties rule | 8 | AppendVertices | 7 | { "props": "[{\"tagId\":10,\"props\":[\"name\"]}]" } | | 7 | Traverse | 6 | { "vertexProps": "[{\"tagId\":9,\"props\":[\"name\"]}]", "edgeProps": "[{\"type\": -5, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"type\": 5, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": -3}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 3}, {\"type\": -4, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 4}]" } | | 6 | Argument | | | - | 31 | Start | | | | 30 | Project | 12 | | | 12 | AppendVertices | 11 | { "props": "[{\"props\":[\"name\"],\"tagId\":9}]" } | | 11 | Traverse | 10 | { "vertexProps": "[{\"props\":[\"name\"],\"tagId\":10}]", "edgeProps": "[{\"type\": -5, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"type\": 5, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": -3}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 3}, {\"type\": -4, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 4}]" } | - | 10 | Argument | | | + | 10 | Argument | 0 | | + | 0 | Start | | | # The schema id is not fixed in standalone cluster, so we skip it @distonly @@ -263,7 +264,6 @@ Feature: Prune Properties rule | 10 | AppendVertices | 9 | { "props": "[{\"tagId\":9,\"props\":[\"name\"]}, {\"tagId\":10,\"props\":[\"name\"]}]" } | | 9 | Traverse | 8 | { "vertexProps": "[{\"tagId\":9,\"props\":[\"name\"]}]" } | | 8 | Argument | | | - | 33 | Start | | | When profiling query: """ MATCH (m)-[]-(n) WHERE id(m)=="Tim Duncan" @@ -299,12 +299,10 @@ Feature: Prune Properties rule | 10 | AppendVertices | 9 | { "props": "[{\"tagId\":10,\"props\":[\"name\"]}]" } | | 9 | Traverse | 8 | { "vertexProps": "[{\"tagId\":9,\"props\":[\"name\"]}]" } | | 8 | Argument | | | - | 35 | Start | | | | 34 | Project | 13 | | | 13 | AppendVertices | 12 | { "props": "[{\"tagId\":9,\"props\":[\"name\"]}]" } | | 12 | Traverse | 11 | { "vertexProps": "[{\"tagId\":10,\"props\":[\"name\"]}]", "edgeProps": "[{\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": -5}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 5}, {\"type\": -3, \"props\": [\"_dst\", \"_rank\", \"_type\"]}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 3}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": -4}, {\"props\": [\"_dst\", \"_rank\", \"_type\"], \"type\": 4}]" } | | 11 | Argument | | | - | 36 | Start | | | When profiling query: """ MATCH (v:player{name:"Tony Parker"}) @@ -327,7 +325,8 @@ Feature: Prune Properties rule | 9 | Project | 8 | | | 8 | AppendVertices | 7 | { "props": "[{\"props\":[\"name\"],\"tagId\":9}]" } | | 7 | Traverse | 6 | { "vertexProps": "", "edgeProps": "[{\"type\": -5, \"props\": [\"_type\", \"_rank\", \"_dst\"]}, {\"props\": [\"_type\", \"_rank\", \"_dst\"], \"type\": -3}, {\"props\": [\"_type\", \"_rank\", \"_dst\"], \"type\": -4}]" } | - | 6 | Argument | | | + | 6 | Argument | 0 | | + | 0 | Start | | | # The schema id is not fixed in standalone cluster, so we skip it @distonly @@ -365,7 +364,8 @@ Feature: Prune Properties rule | 11 | Project | 10 | | | 10 | AppendVertices | 9 | { "props": "[{\"props\":[\"name\", \"age\", \"_tag\"],\"tagId\":9}, {\"props\":[\"name\", \"speciality\", \"_tag\"],\"tagId\":8}, {\"props\":[\"name\", \"_tag\"],\"tagId\":10}]" } | | 9 | Traverse | 8 | { "vertexProps": "[{\"props\":[\"name\"],\"tagId\":9}]" } | - | 8 | Argument | | | + | 8 | Argument | 0 | | + | 0 | Start | | | When profiling query: """ MATCH (m:player{name:"Tim Duncan"})-[:like]-(n)--() @@ -388,7 +388,8 @@ Feature: Prune Properties rule | 11 | Project | 10 | | | 10 | AppendVertices | 9 | { "props": "[{\"props\":[\"_tag\"],\"tagId\":8}, {\"props\":[\"_tag\"],\"tagId\":9}, {\"props\":[\"_tag\"],\"tagId\":10}]" } | | 9 | Traverse | 8 | { "vertexProps": "" } | - | 8 | Argument | | | + | 8 | Argument | 0 | | + | 0 | Start | | | @distonly Scenario: return function @@ -479,7 +480,6 @@ Feature: Prune Properties rule | 18 | AppendVertices | 10 | { "props": "[{\"props\":[\"_tag\"],\"tagId\":10}]" } | | 10 | Traverse | 8 | {"vertexProps": "[{\"props\":[\"name\", \"age\", \"_tag\"],\"tagId\":9}, {\"props\":[\"name\", \"speciality\", \"_tag\"],\"tagId\":8}, {\"props\":[\"name\", \"_tag\"],\"tagId\":10}]", "edgeProps": "[{\"type\": 4, \"props\": [\"_type\", \"_rank\", \"_dst\"]}]" } | | 8 | Argument | | | - | 9 | Start | | | @distonly Scenario: union match @@ -554,7 +554,6 @@ Feature: Prune Properties rule | 14 | Traverse | 13 | {"vertexProps": "", "edgeProps": "[{\"type\": -3, \"props\": [\"_type\", \"_rank\", \"_dst\"]}]" } | | 13 | Traverse | 11 | {"vertexProps": "", "edgeProps": "[{\"type\": -3, \"props\": [\"_type\", \"_rank\", \"_dst\"]}, {\"type\": 3, \"props\": [\"_type\", \"_rank\", \"_dst\"]}]" } | | 11 | Argument | | | - | 12 | Start | | | @distonly Scenario: test properties: @@ -742,9 +741,9 @@ Feature: Prune Properties rule """ Then the result should be, in order, with relax comparison: | properties(src_v).age | properties(e).degree | name | src_v.player.sex | e.start_year | dst_v.player.age | - | 41 | UNKNOWN_PROP | "Dejounte Murray" | "男" | 2022 | 29 | + | 41 | __NULL__ | "Dejounte Murray" | "男" | 2022 | 29 | | 41 | 88 | "Spurs" | "男" | 2002 | NULL | - | 41 | UNKNOWN_PROP | "Tiago Splitter" | "男" | 2022 | 34 | + | 41 | __NULL__ | "Tiago Splitter" | "男" | 2022 | 34 | When executing query: """ match (src_v:player{name:"Manu Ginobili"})-[e*2]-(dst_v) @@ -754,10 +753,10 @@ Feature: Prune Properties rule Then the result should be, in order, with relax comparison: | properties(src_v).sex | properties(e[0]).degree | properties(dst_v).name | age | e[1].start_year | dst_v.player.age | | "男" | 88 | "Danny Green" | 41 | 2010 | 31 | - | "男" | UNKNOWN_PROP | "Danny Green" | 41 | 2022 | 31 | - | "男" | UNKNOWN_PROP | "LeBron James" | 41 | 2022 | 34 | + | "男" | __NULL__ | "Danny Green" | 41 | 2022 | 31 | + | "男" | __NULL__ | "LeBron James" | 41 | 2022 | 34 | | "男" | 88 | "Cory Joseph" | 41 | 2011 | 27 | - | "男" | UNKNOWN_PROP | "76ers" | 41 | 2017 | NULL | + | "男" | __NULL__ | "76ers" | 41 | 2017 | NULL | When executing query: """ match (src_v:player{name:"Manu Ginobili"})-[e:like*2..3]-(dst_v) @@ -766,11 +765,11 @@ Feature: Prune Properties rule """ Then the result should be, in order, with relax comparison: | properties(src_v).sex | properties(e[0]).degree | properties(dst_v).name | age | e[1].start_year | dst_v.player.age | - | "男" | UNKNOWN_PROP | "Danny Green" | 41 | 2022 | 31 | - | "男" | UNKNOWN_PROP | "Danny Green" | 41 | 2022 | 31 | - | "男" | UNKNOWN_PROP | "Kyle Anderson" | 41 | 2022 | 25 | - | "男" | UNKNOWN_PROP | "LeBron James" | 41 | 2022 | 34 | - | "男" | UNKNOWN_PROP | "Kevin Durant" | 41 | 2022 | 30 | + | "男" | __NULL__ | "Danny Green" | 41 | 2022 | 31 | + | "男" | __NULL__ | "Danny Green" | 41 | 2022 | 31 | + | "男" | __NULL__ | "Kyle Anderson" | 41 | 2022 | 25 | + | "男" | __NULL__ | "LeBron James" | 41 | 2022 | 34 | + | "男" | __NULL__ | "Kevin Durant" | 41 | 2022 | 30 | When executing query: """ match (v1)-->(v2)-->(v3) where id(v1)=="Manu Ginobili" @@ -836,9 +835,9 @@ Feature: Prune Properties rule Then the result should be, in order, with relax comparison: | properties(e).degree | degree | | 88 | 88 | - | UNKNOWN_PROP | 88 | + | __NULL__ | 88 | | 88 | 88 | - | UNKNOWN_PROP | 88 | + | __NULL__ | 88 | | 88 | 88 | When executing query: """ @@ -846,9 +845,36 @@ Feature: Prune Properties rule """ Then the result should be, in order, with relax comparison: | properties(e).degree1 | properties(e).degree1 | e2.a | dst_v.p.name | dst_v.player.sex1 | properties(src_v).name2 | - | UNKNOWN_PROP | UNKNOWN_PROP | NULL | NULL | NULL | UNKNOWN_PROP | - | UNKNOWN_PROP | UNKNOWN_PROP | NULL | NULL | NULL | UNKNOWN_PROP | - | UNKNOWN_PROP | UNKNOWN_PROP | NULL | NULL | NULL | UNKNOWN_PROP | - | UNKNOWN_PROP | UNKNOWN_PROP | NULL | NULL | NULL | UNKNOWN_PROP | - | UNKNOWN_PROP | UNKNOWN_PROP | NULL | NULL | NULL | UNKNOWN_PROP | + | __NULL__ | __NULL__ | NULL | NULL | NULL | __NULL__ | + | __NULL__ | __NULL__ | NULL | NULL | NULL | __NULL__ | + | __NULL__ | __NULL__ | NULL | NULL | NULL | __NULL__ | + | __NULL__ | __NULL__ | NULL | NULL | NULL | __NULL__ | + | __NULL__ | __NULL__ | NULL | NULL | NULL | __NULL__ | Then drop the used space + + Scenario: Project on not exist tag + Given a graph with space named "nba" + When executing query: + """ + MATCH (v:player)-[e:like]->(t) WHERE v.player.name=='Tim Duncan' RETURN v.player.name, v.x.y, v.player.age + """ + Then the result should be, in any order, with relax comparison: + | v.player.name | v.x.y | v.player.age | + | "Tim Duncan" | __NULL__ | 42 | + | "Tim Duncan" | __NULL__ | 42 | + When executing query: + """ + MATCH (v:player)-[:like]->(t) WHERE v.player.name=="Tim Duncan" RETURN v.player.name, properties(v), t + """ + Then the result should be, in any order, with relax comparison: + | v.player.name | properties(v) | t | + | "Tim Duncan" | {age: 42, name: "Tim Duncan", speciality: "psychology"} | ("Tony Parker" :player{age: 36, name: "Tony Parker"}) | + | "Tim Duncan" | {age: 42, name: "Tim Duncan", speciality: "psychology"} | ("Manu Ginobili" :player{age: 41, name: "Manu Ginobili"}) | + When executing query: + """ + MATCH (v:player)-[:like]->(t) WHERE v.player.name=="Tim Duncan" RETURN v.player.name, t.errortag.name, properties(v), t + """ + Then the result should be, in any order, with relax comparison: + | v.player.name | t.errortag.name | properties(v) | t | + | "Tim Duncan" | __NULL__ | {age: 42, name: "Tim Duncan", speciality: "psychology"} | ("Tony Parker" :player{age: 36, name: "Tony Parker"}) | + | "Tim Duncan" | __NULL__ | {age: 42, name: "Tim Duncan", speciality: "psychology"} | ("Manu Ginobili" :player{age: 41, name: "Manu Ginobili"}) | diff --git a/tests/tck/features/parser/nebula.feature b/tests/tck/features/parser/nebula.feature index 7e802ce4155..9d9fc4e09e1 100644 --- a/tests/tck/features/parser/nebula.feature +++ b/tests/tck/features/parser/nebula.feature @@ -17,7 +17,7 @@ Feature: Value parsing | BAD_DATA | BAD_DATA | | BAD_TYPE | BAD_TYPE | | OVERFLOW | ERR_OVERFLOW | - | UNKNOWN_PROP | UNKNOWN_PROP | + | __NULL__ | NULL | | DIV_BY_ZERO | DIV_BY_ZERO | | OUT_OF_RANGE | OUT_OF_RANGE | | 123 | iVal | diff --git a/tests/tck/features/schema/Schema.feature b/tests/tck/features/schema/Schema.feature index 986ac30b16d..d06bc0bad9c 100644 --- a/tests/tck/features/schema/Schema.feature +++ b/tests/tck/features/schema/Schema.feature @@ -96,7 +96,7 @@ Feature: Insert string vid of vertex and edge """ DESCRIBE TAG not_exist """ - Then a ExecutionError should be raised at runtime: Tag not existed! + Then a ExecutionError should be raised at runtime: TagNotFound: Tag not existed! # unreserved keyword When executing query: """ @@ -193,7 +193,7 @@ Feature: Insert string vid of vertex and edge """ DROP TAG not_exist_tag """ - Then a ExecutionError should be raised at runtime: Tag not existed! + Then a ExecutionError should be raised at runtime: TagNotFound: Tag not existed! # drop if exists with not exist tag When executing query: """ @@ -300,7 +300,7 @@ Feature: Insert string vid of vertex and edge """ DESCRIBE EDGE not_exist """ - Then a ExecutionError should be raised at runtime: Edge not existed! + Then a ExecutionError should be raised at runtime: EdgeNotFound: Edge not existed! # create edge with timestamp When executing query: """ @@ -378,7 +378,7 @@ Feature: Insert string vid of vertex and edge """ DROP EDGE not_exist_edge """ - Then a ExecutionError should be raised at runtime: Edge not existed! + Then a ExecutionError should be raised at runtime: EdgeNotFound: Edge not existed! # drop if exists When executing query: """ diff --git a/tests/tck/features/subgraph/subgraph.feature b/tests/tck/features/subgraph/subgraph.feature index 3bd67c539ea..9169159d30f 100644 --- a/tests/tck/features/subgraph/subgraph.feature +++ b/tests/tck/features/subgraph/subgraph.feature @@ -1018,6 +1018,33 @@ Feature: subgraph | <[vertex4]> | <[edge4]> | | <[vertex5]> | [] | + Scenario: Filter on edge type + When executing query: + """ + GET SUBGRAPH FROM 'Tim Duncan' BOTH serve WHERE like.likeness < 90 YIELD vertices as v, edges as e + """ + Then a SemanticError should be raised at runtime: Edge type "like" in filter "(like.likeness<90)" is not in the edge types [serve] + When executing query: + """ + GET SUBGRAPH FROM 'Tim Duncan' BOTH serve,teammate WHERE like.likeness >= 90 YIELD vertices as v, edges as e + """ + Then a SemanticError should be raised at runtime: Edge type "like" in filter "(like.likeness>=90)" is not in the edge types [teammate,serve] + When executing query: + """ + GET SUBGRAPH FROM 'Tim Duncan' BOTH serve WHERE serve.start_year < 1997 YIELD vertices as v, edges as e + """ + Then the result should be, in any order, with relax comparison: + | v | e | + | [("Tim Duncan" :player{} :bachelor{})] | [] | + When executing query: + """ + GET SUBGRAPH FROM 'Tim Duncan' BOTH serve WHERE serve.start_year >= 1997 YIELD vertices as v, edges as e + """ + Then the result should be, in any order, with relax comparison: + | v | e | + | [("Tim Duncan" :player{} :bachelor{})] | [[:serve "Tim Duncan"->"Spurs" @0 {start_year: 1997}]] | + | [("Spurs" :team{})] | [] | + Scenario: Get subgraph in a space which doesn't have edge schema Given an empty graph And create a space with following options: diff --git a/tests/tck/features/yield/NoSpaceChosen.feature b/tests/tck/features/yield/NoSpaceChosen.feature index e83140b13fb..229e571deb7 100644 --- a/tests/tck/features/yield/NoSpaceChosen.feature +++ b/tests/tck/features/yield/NoSpaceChosen.feature @@ -88,12 +88,12 @@ Feature: Yield """ YIELD $$.dummyTag.p """ - Then a ExecutionError should be raised at runtime: TagName `dummyTag' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `dummyTag` When executing query: """ YIELD $^.dummyTag.p """ - Then a ExecutionError should be raised at runtime: TagName `dummyTag' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `dummyTag` When executing query: """ YIELD $-.dummyTag.p diff --git a/tests/tck/features/yield/return.feature b/tests/tck/features/yield/return.feature index d7ebe9fbf12..d18cd814ea8 100644 --- a/tests/tck/features/yield/return.feature +++ b/tests/tck/features/yield/return.feature @@ -62,12 +62,12 @@ Feature: Return """ RETURN $$.dummyTag.p """ - Then a ExecutionError should be raised at runtime: TagName `dummyTag' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `dummyTag` When executing query: """ RETURN $^.dummyTag.p """ - Then a ExecutionError should be raised at runtime: TagName `dummyTag' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `dummyTag` When executing query: """ RETURN $-.dummyTag.p diff --git a/tests/tck/features/yield/yield.IntVid.feature b/tests/tck/features/yield/yield.IntVid.feature index 6fa0c5bd873..0aef1b6b7e6 100644 --- a/tests/tck/features/yield/yield.IntVid.feature +++ b/tests/tck/features/yield/yield.IntVid.feature @@ -298,12 +298,12 @@ Feature: Yield Sentence """ $var = GO FROM hash("Boris Diaw") OVER serve YIELD $^.player.name AS name, serve.start_year AS start, $$.team.name AS team;YIELD $$.a.team """ - Then a ExecutionError should be raised at runtime: TagName `a' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `a` When executing query: """ $var = GO FROM hash("Boris Diaw") OVER serve YIELD $^.player.name AS name, serve.start_year AS start, $$.team.name AS team;YIELD $^.a.team """ - Then a ExecutionError should be raised at runtime: TagName `a' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `a` When executing query: """ $var = GO FROM hash("Boris Diaw") OVER serve YIELD $^.player.name AS name, serve.start_year AS start, $$.team.name AS team;YIELD a.team diff --git a/tests/tck/features/yield/yield.feature b/tests/tck/features/yield/yield.feature index 71afde05e15..47677b2cb3e 100644 --- a/tests/tck/features/yield/yield.feature +++ b/tests/tck/features/yield/yield.feature @@ -308,12 +308,12 @@ Feature: Yield Sentence """ $var = GO FROM "Boris Diaw" OVER serve YIELD $^.player.name AS name, serve.start_year AS start, $$.team.name AS team;YIELD $$.a.team """ - Then a ExecutionError should be raised at runtime: TagName `a' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `a` When executing query: """ $var = GO FROM "Boris Diaw" OVER serve YIELD $^.player.name AS name, serve.start_year AS start, $$.team.name AS team;YIELD $^.a.team """ - Then a ExecutionError should be raised at runtime: TagName `a' is nonexistent + Then a ExecutionError should be raised at runtime: TagNotFound: TagName `a` When executing query: """ $var = GO FROM "Boris Diaw" OVER serve YIELD $^.player.name AS name, serve.start_year AS start, $$.team.name AS team;YIELD a.team diff --git a/tests/tck/utils/nbv.py b/tests/tck/utils/nbv.py index 6bc4e3a1714..fb75b0569ae 100644 --- a/tests/tck/utils/nbv.py +++ b/tests/tck/utils/nbv.py @@ -42,7 +42,7 @@ 'BAD_DATA', 'BAD_TYPE', 'OVERFLOW', - 'UNKNOWN_PROP', + '__NULL__', 'DIV_BY_ZERO', 'OUT_OF_RANGE', 'FLOAT', @@ -100,9 +100,9 @@ def t_OVERFLOW(t): return t -def t_UNKNOWN_PROP(t): - r'UNKNOWN_PROP' - t.value = Value(nVal=NullType.UNKNOWN_PROP) +def t___NULL__(t): + r'__NULL__' + t.value = Value(nVal=NullType.__NULL__) return t @@ -239,7 +239,7 @@ def p_expr(p): | BAD_DATA | BAD_TYPE | OVERFLOW - | UNKNOWN_PROP + | __NULL__ | DIV_BY_ZERO | OUT_OF_RANGE | INT @@ -587,7 +587,7 @@ def parse_row(row): expected['BAD_DATA'] = Value(nVal=NullType.BAD_DATA) expected['BAD_TYPE'] = Value(nVal=NullType.BAD_TYPE) expected['OVERFLOW'] = Value(nVal=NullType.ERR_OVERFLOW) - expected['UNKNOWN_PROP'] = Value(nVal=NullType.UNKNOWN_PROP) + expected['__NULL__'] = Value(nVal=NullType.__NULL__) expected['DIV_BY_ZERO'] = Value(nVal=NullType.DIV_BY_ZERO) expected['OUT_OF_RANGE'] = Value(nVal=NullType.OUT_OF_RANGE) expected['123'] = Value(iVal=123)