From 51e81a717fa9db3c3cfee5fbeb7a1c45ed464008 Mon Sep 17 00:00:00 2001 From: steppenwolfyuetong Date: Fri, 28 Jun 2019 15:39:58 +0800 Subject: [PATCH] Ttl schema (#422) * support time to live alter tag/edge drop column, and the column to be delete is as TTL column * improve unreserved keywords feature * address laura-ding's comment * address dangleptr's comment * address dangleptr's comment * In AlterTagReq/AlterEdgeReq discards AlterSchemaProp, using SchemaProp * address comments * address dangleptr's comments * address comments --- src/graph/AlterEdgeExecutor.cpp | 32 +- src/graph/AlterEdgeExecutor.h | 4 +- src/graph/AlterTagExecutor.cpp | 33 +- src/graph/AlterTagExecutor.h | 4 +- src/graph/CMakeLists.txt | 1 + src/graph/CreateEdgeExecutor.cpp | 23 +- src/graph/CreateEdgeExecutor.h | 1 + src/graph/CreateTagExecutor.cpp | 23 +- src/graph/CreateTagExecutor.h | 1 + src/graph/Executor.cpp | 17 - src/graph/Executor.h | 2 - src/graph/SchemaHelper.cpp | 166 ++++++ src/graph/SchemaHelper.h | 44 ++ src/graph/test/SchemaTest.cpp | 357 +++++++++++- src/interface/common.thrift | 6 + src/interface/meta.thrift | 23 +- src/meta/MetaServiceUtils.cpp | 63 ++- src/meta/MetaServiceUtils.h | 6 + src/meta/NebulaSchemaProvider.cpp | 8 + src/meta/NebulaSchemaProvider.h | 7 +- src/meta/client/MetaClient.cpp | 13 +- src/meta/client/MetaClient.h | 6 +- src/meta/processors/BaseProcessor.h | 2 +- .../schemaMan/AlterEdgeProcessor.cpp | 21 +- .../schemaMan/AlterTagProcessor.cpp | 21 +- src/meta/test/ProcessorTest.cpp | 510 ++++++++++++------ src/parser/MaintainSentences.h | 6 +- src/parser/parser.yy | 8 + 28 files changed, 1131 insertions(+), 277 deletions(-) create mode 100644 src/graph/SchemaHelper.cpp create mode 100644 src/graph/SchemaHelper.h diff --git a/src/graph/AlterEdgeExecutor.cpp b/src/graph/AlterEdgeExecutor.cpp index 8c7858d6dc7..91eb9ca7bf8 100644 --- a/src/graph/AlterEdgeExecutor.cpp +++ b/src/graph/AlterEdgeExecutor.cpp @@ -6,6 +6,7 @@ #include "base/Base.h" #include "graph/AlterEdgeExecutor.h" +#include "graph/SchemaHelper.h" namespace nebula { namespace graph { @@ -17,34 +18,25 @@ AlterEdgeExecutor::AlterEdgeExecutor(Sentence *sentence, Status AlterEdgeExecutor::prepare() { - return checkIfGraphSpaceChosen(); + auto status = checkIfGraphSpaceChosen(); + + if (!status.ok()) { + return status; + } + + const auto& schemaOpts = sentence_->getSchemaOpts(); + const auto& schemaProps = sentence_->getSchemaProps(); + + return SchemaHelper::alterSchema(schemaOpts, schemaProps, options_, schemaProp_); } void AlterEdgeExecutor::execute() { auto *mc = ectx()->getMetaClient(); auto *name = sentence_->name(); - const auto& schemaOpts = sentence_->schemaOptList(); auto spaceId = ectx()->rctx()->session()->space(); - std::vector schemaItems; - for (auto& schemaOpt : schemaOpts) { - nebula::meta::cpp2::AlterSchemaItem schemaItem; - auto opType = schemaOpt->toType(); - schemaItem.set_op(std::move(opType)); - const auto& specs = schemaOpt->columnSpecs(); - nebula::cpp2::Schema schema; - for (auto& spec : specs) { - nebula::cpp2::ColumnDef column; - column.name = *spec->name(); - column.type.type = columnTypeToSupportedType(spec->type()); - schema.columns.emplace_back(std::move(column)); - } - schemaItem.set_schema(std::move(schema)); - schemaItems.emplace_back(std::move(schemaItem)); - } - - auto future = mc->alterEdgeSchema(spaceId, *name, std::move(schemaItems)); + auto future = mc->alterEdgeSchema(spaceId, *name, std::move(options_), std::move(schemaProp_)); auto *runner = ectx()->rctx()->runner(); auto cb = [this] (auto &&resp) { if (!resp.ok()) { diff --git a/src/graph/AlterEdgeExecutor.h b/src/graph/AlterEdgeExecutor.h index 72995c930f0..7a1f2906e97 100644 --- a/src/graph/AlterEdgeExecutor.h +++ b/src/graph/AlterEdgeExecutor.h @@ -26,7 +26,9 @@ class AlterEdgeExecutor final : public Executor { void execute() override; private: - AlterEdgeSentence *sentence_{nullptr}; + AlterEdgeSentence *sentence_{nullptr}; + std::vector options_; + nebula::cpp2::SchemaProp schemaProp_; }; } // namespace graph diff --git a/src/graph/AlterTagExecutor.cpp b/src/graph/AlterTagExecutor.cpp index de4ed7e0c7c..6a34d945b38 100644 --- a/src/graph/AlterTagExecutor.cpp +++ b/src/graph/AlterTagExecutor.cpp @@ -6,6 +6,7 @@ #include "base/Base.h" #include "graph/AlterTagExecutor.h" +#include "graph/SchemaHelper.h" namespace nebula { namespace graph { @@ -15,34 +16,28 @@ AlterTagExecutor::AlterTagExecutor(Sentence *sentence, sentence_ = static_cast(sentence); } + Status AlterTagExecutor::prepare() { - return checkIfGraphSpaceChosen(); + auto status = checkIfGraphSpaceChosen(); + + if (!status.ok()) { + return status; + } + + const auto& schemaOpts = sentence_->getSchemaOpts(); + const auto& schemaProps = sentence_->getSchemaProps(); + + return SchemaHelper::alterSchema(schemaOpts, schemaProps, options_, schemaProp_); } + void AlterTagExecutor::execute() { auto *mc = ectx()->getMetaClient(); auto *name = sentence_->name(); - const auto& schemaOpts = sentence_->schemaOptList(); auto spaceId = ectx()->rctx()->session()->space(); - std::vector schemaItems; - for (auto& schemaOpt : schemaOpts) { - nebula::meta::cpp2::AlterSchemaItem schemaItem; - auto opType = schemaOpt->toType(); - schemaItem.set_op(std::move(opType)); - const auto& specs = schemaOpt->columnSpecs(); - nebula::cpp2::Schema schema; - for (auto& spec : specs) { - nebula::cpp2::ColumnDef column; - column.name = *spec->name(); - column.type.type = columnTypeToSupportedType(spec->type()); - schema.columns.emplace_back(std::move(column)); - } - schemaItem.set_schema(std::move(schema)); - schemaItems.emplace_back(std::move(schemaItem)); - } - auto future = mc->alterTagSchema(spaceId, *name, std::move(schemaItems)); + auto future = mc->alterTagSchema(spaceId, *name, std::move(options_), std::move(schemaProp_)); auto *runner = ectx()->rctx()->runner(); auto cb = [this] (auto &&resp) { if (!resp.ok()) { diff --git a/src/graph/AlterTagExecutor.h b/src/graph/AlterTagExecutor.h index 5e2b2b4a37a..ab7c6f14195 100644 --- a/src/graph/AlterTagExecutor.h +++ b/src/graph/AlterTagExecutor.h @@ -26,7 +26,9 @@ class AlterTagExecutor final : public Executor { void execute() override; private: - AlterTagSentence *sentence_{nullptr}; + AlterTagSentence *sentence_{nullptr}; + std::vector options_; + nebula::cpp2::SchemaProp schemaProp_; }; } // namespace graph diff --git a/src/graph/CMakeLists.txt b/src/graph/CMakeLists.txt index 3f038779b81..2e67a65e4a4 100644 --- a/src/graph/CMakeLists.txt +++ b/src/graph/CMakeLists.txt @@ -33,6 +33,7 @@ add_library( DescribeSpaceExecutor.cpp ShowExecutor.cpp YieldExecutor.cpp + SchemaHelper.cpp ) add_dependencies( graph_obj diff --git a/src/graph/CreateEdgeExecutor.cpp b/src/graph/CreateEdgeExecutor.cpp index d926b3899df..93d903c873c 100644 --- a/src/graph/CreateEdgeExecutor.cpp +++ b/src/graph/CreateEdgeExecutor.cpp @@ -7,6 +7,7 @@ #include "base/Base.h" #include "graph/CreateEdgeExecutor.h" #include "dataman/ResultSchemaProvider.h" +#include "graph/SchemaHelper.h" namespace nebula { namespace graph { @@ -18,25 +19,25 @@ CreateEdgeExecutor::CreateEdgeExecutor(Sentence *sentence, Status CreateEdgeExecutor::prepare() { - return checkIfGraphSpaceChosen(); + auto status = checkIfGraphSpaceChosen(); + + if (!status.ok()) { + return status; + } + + const auto& specs = sentence_->columnSpecs(); + const auto& schemaProps = sentence_->getSchemaProps(); + + return SchemaHelper::createSchema(specs, schemaProps, schema_); } void CreateEdgeExecutor::execute() { auto *mc = ectx()->getMetaClient(); auto *name = sentence_->name(); - const auto& specs = sentence_->columnSpecs(); auto spaceId = ectx()->rctx()->session()->space(); - nebula::cpp2::Schema schema; - for (auto& spec : specs) { - nebula::cpp2::ColumnDef column; - column.name = *spec->name(); - column.type.type = columnTypeToSupportedType(spec->type()); - schema.columns.emplace_back(std::move(column)); - } - - auto future = mc->createEdgeSchema(spaceId, *name, schema); + auto future = mc->createEdgeSchema(spaceId, *name, schema_); auto *runner = ectx()->rctx()->runner(); auto cb = [this] (auto &&resp) { if (!resp.ok()) { diff --git a/src/graph/CreateEdgeExecutor.h b/src/graph/CreateEdgeExecutor.h index a175fabc624..ba185c50998 100644 --- a/src/graph/CreateEdgeExecutor.h +++ b/src/graph/CreateEdgeExecutor.h @@ -27,6 +27,7 @@ class CreateEdgeExecutor final : public Executor { private: CreateEdgeSentence *sentence_{nullptr}; + nebula::cpp2::Schema schema_; }; } // namespace graph diff --git a/src/graph/CreateTagExecutor.cpp b/src/graph/CreateTagExecutor.cpp index fdc97c7ce4b..52fca65ff45 100644 --- a/src/graph/CreateTagExecutor.cpp +++ b/src/graph/CreateTagExecutor.cpp @@ -7,6 +7,7 @@ #include "base/Base.h" #include "graph/CreateTagExecutor.h" #include "dataman/ResultSchemaProvider.h" +#include "graph/SchemaHelper.h" namespace nebula { namespace graph { @@ -18,25 +19,25 @@ CreateTagExecutor::CreateTagExecutor(Sentence *sentence, Status CreateTagExecutor::prepare() { - return checkIfGraphSpaceChosen(); + auto status = checkIfGraphSpaceChosen(); + + if (!status.ok()) { + return status; + } + + const auto& specs = sentence_->columnSpecs(); + const auto& schemaProps = sentence_->getSchemaProps(); + + return SchemaHelper::createSchema(specs, schemaProps, schema_); } void CreateTagExecutor::execute() { auto *mc = ectx()->getMetaClient(); auto *name = sentence_->name(); - const auto& specs = sentence_->columnSpecs(); auto spaceId = ectx()->rctx()->session()->space(); - nebula::cpp2::Schema schema; - for (auto& spec : specs) { - nebula::cpp2::ColumnDef column; - column.name = *spec->name(); - column.type.type = columnTypeToSupportedType(spec->type()); - schema.columns.emplace_back(std::move(column)); - } - - auto future = mc->createTagSchema(spaceId, *name, schema); + auto future = mc->createTagSchema(spaceId, *name, schema_); auto *runner = ectx()->rctx()->runner(); auto cb = [this] (auto &&resp) { if (!resp.ok()) { diff --git a/src/graph/CreateTagExecutor.h b/src/graph/CreateTagExecutor.h index 7d8f59493a9..11d19f4d44a 100644 --- a/src/graph/CreateTagExecutor.h +++ b/src/graph/CreateTagExecutor.h @@ -27,6 +27,7 @@ class CreateTagExecutor final : public Executor { private: CreateTagSentence *sentence_{nullptr}; + nebula::cpp2::Schema schema_; }; } // namespace graph diff --git a/src/graph/Executor.cpp b/src/graph/Executor.cpp index f1e9a4147fe..9e9722716dd 100644 --- a/src/graph/Executor.cpp +++ b/src/graph/Executor.cpp @@ -129,23 +129,6 @@ std::string Executor::valueTypeToString(nebula::cpp2::ValueType type) { } } -nebula::cpp2::SupportedType Executor::columnTypeToSupportedType(ColumnType type) { - switch (type) { - case BOOL: - return nebula::cpp2::SupportedType::BOOL; - case INT: - return nebula::cpp2::SupportedType::INT; - case DOUBLE: - return nebula::cpp2::SupportedType::DOUBLE; - case STRING: - return nebula::cpp2::SupportedType::STRING; - case TIMESTAMP: - return nebula::cpp2::SupportedType::TIMESTAMP; - default: - return nebula::cpp2::SupportedType::UNKNOWN; - } -} - void Executor::writeVariantType(RowWriter &writer, const VariantType &value) { switch (value.which()) { case 0: diff --git a/src/graph/Executor.h b/src/graph/Executor.h index 00d8a9e22c3..cd6969d1dab 100644 --- a/src/graph/Executor.h +++ b/src/graph/Executor.h @@ -78,8 +78,6 @@ class Executor : public cpp::NonCopyable, public cpp::NonMovable { std::string valueTypeToString(nebula::cpp2::ValueType type); - nebula::cpp2::SupportedType columnTypeToSupportedType(ColumnType type); - void writeVariantType(RowWriter &writer, const VariantType &value); bool checkValueType(const nebula::cpp2::ValueType &type, const VariantType &value); diff --git a/src/graph/SchemaHelper.cpp b/src/graph/SchemaHelper.cpp new file mode 100644 index 00000000000..295b26b8417 --- /dev/null +++ b/src/graph/SchemaHelper.cpp @@ -0,0 +1,166 @@ +/* Copyright (c) 2019 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "base/Base.h" +#include "graph/SchemaHelper.h" +#include "graph/Executor.h" + +namespace nebula { +namespace graph { + +// static +nebula::cpp2::SupportedType SchemaHelper::columnTypeToSupportedType(ColumnType type) { + switch (type) { + case BOOL: + return nebula::cpp2::SupportedType::BOOL; + case INT: + return nebula::cpp2::SupportedType::INT; + case DOUBLE: + return nebula::cpp2::SupportedType::DOUBLE; + case STRING: + return nebula::cpp2::SupportedType::STRING; + case TIMESTAMP: + return nebula::cpp2::SupportedType::TIMESTAMP; + default: + return nebula::cpp2::SupportedType::UNKNOWN; + } +} + +// static +Status SchemaHelper::createSchema(const std::vector& specs, + const std::vector& schemaProps, + nebula::cpp2::Schema& schema) { + auto status = Status::OK(); + + for (auto& spec : specs) { + nebula::cpp2::ColumnDef column; + column.name = *spec->name(); + column.type.type = columnTypeToSupportedType(spec->type()); + schema.columns.emplace_back(std::move(column)); + } + + if (!schemaProps.empty()) { + for (auto& schemaProp : schemaProps) { + switch (schemaProp->getPropType()) { + case SchemaPropItem::TTL_DURATION: + status = setTTLDuration(schemaProp, schema); + if (!status.ok()) { + return status; + } + break; + case SchemaPropItem::TTL_COL: + status = setTTLCol(schemaProp, schema); + if (!status.ok()) { + return status; + } + break; + } + } + + if (schema.schema_prop.get_ttl_duration() && + (*schema.schema_prop.get_ttl_duration() != 0)) { + // Disable implicit TTL mode + if (!schema.schema_prop.get_ttl_col() || + (schema.schema_prop.get_ttl_col() && schema.schema_prop.get_ttl_col()->empty())) { + return Status::Error("Implicit ttl_col not support"); + } + } + } + + return Status::OK(); +} + + +// static +Status SchemaHelper::setTTLDuration(SchemaPropItem* schemaProp, nebula::cpp2::Schema& schema) { + auto ret = schemaProp->getTtlDuration(); + if (!ret.ok()) { + return ret.status(); + } + + auto ttlDuration = ret.value(); + schema.schema_prop.set_ttl_duration(ttlDuration); + return Status::OK(); +} + + +// static +Status SchemaHelper::setTTLCol(SchemaPropItem* schemaProp, nebula::cpp2::Schema& schema) { + auto ret = schemaProp->getTtlCol(); + if (!ret.ok()) { + return ret.status(); + } + + auto ttlColName = ret.value(); + // Check the legality of the ttl column name + for (auto& col : schema.columns) { + if (col.name == ttlColName) { + // Only integer columns and timestamp columns can be used as ttl_col + // TODO(YT) Ttl_duration supports datetime type + if (col.type.type != nebula::cpp2::SupportedType::INT && + col.type.type != nebula::cpp2::SupportedType::TIMESTAMP) { + return Status::Error("Ttl column type illegal"); + } + schema.schema_prop.set_ttl_col(ttlColName); + return Status::OK(); + } + } + return Status::Error("Ttl column name not exist in columns"); +} + + +// static +Status SchemaHelper::alterSchema(const std::vector& schemaOpts, + const std::vector& schemaProps, + std::vector& options, + nebula::cpp2::SchemaProp& prop) { + for (auto& schemaOpt : schemaOpts) { + nebula::meta::cpp2::AlterSchemaItem schemaItem; + auto opType = schemaOpt->toType(); + schemaItem.set_op(std::move(opType)); + const auto& specs = schemaOpt->columnSpecs(); + nebula::cpp2::Schema schema; + for (auto& spec : specs) { + nebula::cpp2::ColumnDef column; + column.name = *spec->name(); + column.type.type = columnTypeToSupportedType(spec->type()); + schema.columns.emplace_back(std::move(column)); + } + schemaItem.set_schema(std::move(schema)); + options.emplace_back(std::move(schemaItem)); + } + + for (auto& schemaProp : schemaProps) { + auto propType = schemaProp->getPropType(); + StatusOr retInt; + StatusOr retStr; + int ttlDuration; + switch (propType) { + case SchemaPropItem::TTL_DURATION: + retInt = schemaProp->getTtlDuration(); + if (!retInt.ok()) { + return retInt.status(); + } + ttlDuration = retInt.value(); + prop.set_ttl_duration(ttlDuration); + break; + case SchemaPropItem::TTL_COL: + // Check the legality of the column in meta + retStr = schemaProp->getTtlCol(); + if (!retStr.ok()) { + return retStr.status(); + } + prop.set_ttl_col(retStr.value()); + break; + default: + return Status::Error("Property type not support"); + } + } + return Status::OK(); +} + +} // namespace graph +} // namespace nebula diff --git a/src/graph/SchemaHelper.h b/src/graph/SchemaHelper.h new file mode 100644 index 00000000000..f9d68ad2bed --- /dev/null +++ b/src/graph/SchemaHelper.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2019 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#ifndef GRAPH_SCHEMAHELPER_H_ +#define GRAPH_SCHEMAHELPER_H_ + +#include "base/Base.h" +#include "base/Status.h" +#include "gen-cpp2/common_types.h" +#include "parser/MaintainSentences.h" + +/** + * SchemaHelper is the interface of `create schema' used in `create tag/edge' and `alter schema' + * used in `alter tag/edge'. + */ + +namespace nebula { +namespace graph { + +class SchemaHelper final { +public: + static Status createSchema(const std::vector& specs, + const std::vector& schemaProps, + nebula::cpp2::Schema& schema); + + static Status setTTLDuration(SchemaPropItem* schemaProp, nebula::cpp2::Schema& schema); + + static Status setTTLCol(SchemaPropItem* schemaProp, nebula::cpp2::Schema& schema); + + static Status alterSchema(const std::vector& schemaOpts, + const std::vector& schemaProps, + std::vector& options, + nebula::cpp2::SchemaProp& schemaProp); + + static nebula::cpp2::SupportedType columnTypeToSupportedType(ColumnType type); +}; + +} // namespace graph +} // namespace nebula + +#endif // GRAPH_SCHEMAHELPER_H_ diff --git a/src/graph/test/SchemaTest.cpp b/src/graph/test/SchemaTest.cpp index bf2b215ed10..1692550973e 100644 --- a/src/graph/test/SchemaTest.cpp +++ b/src/graph/test/SchemaTest.cpp @@ -48,6 +48,8 @@ TEST_F(SchemaTest, metaCommunication) { }; ASSERT_TRUE(verifyResult(resp, expected)); } + + // Space test { // Test space not exist cpp2::ExecutionResponse resp; @@ -109,6 +111,8 @@ TEST_F(SchemaTest, metaCommunication) { auto code = client->execute(query, resp); ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); } + + // Tag test { cpp2::ExecutionResponse resp; std::string query = "CREATE TAG person(name string, email string, " @@ -145,7 +149,7 @@ TEST_F(SchemaTest, metaCommunication) { ASSERT_TRUE(verifyResult(resp, expected)); } { - // Test the tag has been existed. + // Unreserved keyword test cpp2::ExecutionResponse resp; std::string query = "CREATE TAG upper(name string, EMAIL string, " "age int, gender string, row_timestamp timestamp)"; @@ -174,7 +178,7 @@ TEST_F(SchemaTest, metaCommunication) { ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); } { - // Test exist + // Tag has existed cpp2::ExecutionResponse resp; std::string query = "CREATE TAG account(id int, balance double)"; auto code = client->execute(query, resp); @@ -213,6 +217,8 @@ TEST_F(SchemaTest, metaCommunication) { auto code = client->execute(query, resp); ASSERT_EQ(cpp2::ErrorCode::E_EXECUTION_ERROR, code); } + + // Edge test { cpp2::ExecutionResponse resp; std::string query = "CREATE EDGE buy(id int, time string)"; @@ -236,13 +242,6 @@ TEST_F(SchemaTest, metaCommunication) { }; EXPECT_TRUE(verifyResult(resp, expected)); } - { - // Test edge not exist - cpp2::ExecutionResponse resp; - std::string query = "DESCRIBE EDGE not_exist"; - auto code = client->execute(query, resp); - ASSERT_EQ(cpp2::ErrorCode::E_EXECUTION_ERROR, code); - } { cpp2::ExecutionResponse resp; std::string query = "DESC EDGE buy"; @@ -253,6 +252,13 @@ TEST_F(SchemaTest, metaCommunication) { }; EXPECT_TRUE(verifyResult(resp, expected)); } + { + // Test edge not exist + cpp2::ExecutionResponse resp; + std::string query = "DESCRIBE EDGE not_exist"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::E_EXECUTION_ERROR, code); + } { cpp2::ExecutionResponse resp; std::string query = "CREATE EDGE education(id int, time timestamp, school string)"; @@ -307,6 +313,8 @@ TEST_F(SchemaTest, metaCommunication) { }; ASSERT_TRUE(verifyResult(resp, expected)); } + + // Test different tag and edge in different space { cpp2::ExecutionResponse resp; std::string query = "CREATE SPACE my_space(partition_num=9, replica_factor=1)"; @@ -319,7 +327,6 @@ TEST_F(SchemaTest, metaCommunication) { auto code = client->execute(query, resp); ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); } - // Test different tag and edge in different space { cpp2::ExecutionResponse resp; std::string query = "CREATE TAG animal(name string, kind string)"; @@ -401,5 +408,335 @@ TEST_F(SchemaTest, metaCommunication) { } } + +TEST_F(SchemaTest, TTLtest) { + auto client = gEnv->getClient(); + ASSERT_NE(nullptr, client); + { + cpp2::ExecutionResponse resp; + std::string query = "ADD HOSTS 127.0.0.1:1000, 127.0.0.1:1100"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + meta::TestUtils::registerHB( + network::NetworkUtils::toHosts("127.0.0.1:1000, 127.0.0.1:1100").value()); + } + { + cpp2::ExecutionResponse resp; + std::string query = "SHOW HOSTS"; + client->execute(query, resp); + std::vector> expected{ + {"127.0.0.1", "1000", "offline"}, + {"127.0.0.1", "1100", "offline"}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE SPACE default_space(partition_num=9, replica_factor=1)"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "USE default_space"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + + // Tag with TTL test + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE TAG person(name string, email string, " + "age int, gender string, row_timestamp timestamp)"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "DESCRIBE TAG person"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector> expected{ + {"name", "string"}, + {"email", "string"}, + {"age", "int"}, + {"gender", "string"}, + {"row_timestamp", "timestamp"}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + // TODO(YT) Add show create tag + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE TAG man(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_duration = 100, ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "DESCRIBE TAG man"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + + std::vector> expected{ + {"name", "string"}, + {"email", "string"}, + {"age", "int"}, + {"gender", "string"}, + {"row_timestamp", "timestamp"}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + // Add show create tag test + { + // Disable implicit ttl mode + cpp2::ExecutionResponse resp; + std::string query = "CREATE TAG woman(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_duration = 100"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + { + // Disable when ttl_col is not an integer column or a timestamp column + cpp2::ExecutionResponse resp; + std::string query = "CREATE TAG woman(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_col = name"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE TAG woman(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_duration = -100, ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create tag instead + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE TAG only_ttl_col(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create tag instead + { + cpp2::ExecutionResponse resp; + std::string query = "ALTER TAG woman " + "ttl_duration = 50, ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // Use show create tag instead + { + cpp2::ExecutionResponse resp; + std::string query = "DESCRIBE TAG woman"; + client->execute(query, resp); + std::vector> expected{ + {"name", "string"}, + {"email", "string"}, + {"age", "int"}, + {"gender", "string"}, + {"row_timestamp", "timestamp"}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + // Failed when alter tag to set ttl_col on not integer and timestamp column + cpp2::ExecutionResponse resp; + std::string query = "ALTER TAG woman " + "ttl_col = name"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + // Use show create tag instead + { + cpp2::ExecutionResponse resp; + std::string query = "DESCRIBE TAG woman"; + client->execute(query, resp); + std::vector> expected{ + {"name", "string"}, + {"email", "string"}, + {"age", "int"}, + {"gender", "string"}, + {"row_timestamp", "timestamp"}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + cpp2::ExecutionResponse resp; + std::string query = "ALTER TAG woman " + "Drop (name) ttl_duration = 200"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create tag + { + // When the column is as TTL column, droping column failed + cpp2::ExecutionResponse resp; + std::string query = "ALTER TAG woman " + "Drop (row_timestamp)"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create tag + { + // First remove TTL property, then drop column + cpp2::ExecutionResponse resp; + std::string query = "ALTER TAG woman " + "ttl_col = age"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create tag + { + cpp2::ExecutionResponse resp; + std::string query = "ALTER TAG woman " + "Drop (row_timestamp)"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create tag + + // Edge ttl test + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE EDGE person(name string, email string, " + "age int, gender string, row_timestamp timestamp)"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "DESCRIBE EDGE person"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector> expected{ + {"name", "string"}, + {"email", "string"}, + {"age", "int"}, + {"gender", "string"}, + {"row_timestamp", "timestamp"}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + // TODO(YT) Use show create edge test + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE EDGE man(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_duration = 100, ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge test + { + // Disable implicit ttl mode + cpp2::ExecutionResponse resp; + std::string query = "CREATE EDGE woman(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_duration = 100"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + { + // Disable when ttl_col is not an integer column or a timestamp column + cpp2::ExecutionResponse resp; + std::string query = "CREATE EDGE woman(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_col = name"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE EDGE woman(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_duration = -100, ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + cpp2::ExecutionResponse resp; + std::string query = "CREATE EDGE only_ttl_col(name string, email string, " + "age int, gender string, row_timestamp timestamp)" + "ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + cpp2::ExecutionResponse resp; + std::string query = "ALTER EDGE woman " + "ttl_duration = 50, ttl_col = row_timestamp"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + cpp2::ExecutionResponse resp; + std::string query = "ALTER EDGE woman " + "Drop (name) ttl_duration = 200"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + // Failed when alter tag to set ttl_col on not integer and timestamp column + cpp2::ExecutionResponse resp; + std::string query = "ALTER EDGE woman " + "ttl_col = email"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + // When the column is as TTL column, droping column failed + cpp2::ExecutionResponse resp; + std::string query = "ALTER EDGE woman " + "Drop (row_timestamp)"; + auto code = client->execute(query, resp); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + // First remove TTL property, then drop column + cpp2::ExecutionResponse resp; + std::string query = "ALTER EDGE woman " + "ttl_col = age"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + { + cpp2::ExecutionResponse resp; + std::string query = "ALTER EDGE woman " + "drop (row_timestamp)"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // TODO(YT) Use show create edge + + { + cpp2::ExecutionResponse resp; + std::string query = "DROP SPACE default_space"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + { + cpp2::ExecutionResponse resp; + std::string query = "REMOVE HOSTS 127.0.0.1:1000, 127.0.0.1:1100"; + auto code = client->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } +} + } // namespace graph } // namespace nebula diff --git a/src/interface/common.thrift b/src/interface/common.thrift index 0472528e897..e3a0666432f 100644 --- a/src/interface/common.thrift +++ b/src/interface/common.thrift @@ -68,8 +68,14 @@ struct ColumnDef { 2: required ValueType type, } +struct SchemaProp { + 1: optional i64 ttl_duration, + 2: optional string ttl_col, +} + struct Schema { 1: list columns, + 2: SchemaProp schema_prop, } struct HostAddr { diff --git a/src/interface/meta.thrift b/src/interface/meta.thrift index f42c6d85edc..155339b31b0 100644 --- a/src/interface/meta.thrift +++ b/src/interface/meta.thrift @@ -26,6 +26,7 @@ enum ErrorCode { E_NOT_FOUND = -23, E_INVALID_HOST = -24, E_UNSUPPORTED = -25, + E_NOT_DROP = -26, // KV Failure E_STORE_FAILURE = -31, @@ -37,7 +38,6 @@ enum ErrorCode { E_UNKNOWN = -99, } (cpp.enum_strict) - enum AlterSchemaOp { ADD = 0x01, CHANGE = 0x02, @@ -60,7 +60,6 @@ enum RoleType { GUEST = 0x04, } (cpp.enum_strict) - union ID { 1: common.GraphSpaceID space_id, 2: common.TagID tag_id, @@ -184,9 +183,10 @@ struct CreateTagReq { } struct AlterTagReq { - 1: common.GraphSpaceID space_id, - 2: string tag_name, - 3: list tag_items, + 1: common.GraphSpaceID space_id, + 2: string tag_name, + 3: list tag_items, + 4: common.SchemaProp schema_prop, } struct DropTagReq { @@ -225,9 +225,10 @@ struct CreateEdgeReq { } struct AlterEdgeReq { - 1: common.GraphSpaceID space_id, - 2: string edge_name, - 3: list edge_items, + 1: common.GraphSpaceID space_id, + 2: string edge_name, + 3: list edge_items, + 4: common.SchemaProp schema_prop, } struct GetEdgeReq { @@ -380,7 +381,7 @@ struct GetUserReq { struct GetUserResp { 1: ErrorCode code, // Valid if ret equals E_LEADER_CHANGED. - 2: common.HostAddr leader, + 2: common.HostAddr leader, 3: UserItem user_item, } @@ -390,7 +391,7 @@ struct ListUsersReq { struct ListUsersResp { 1: ErrorCode code, // Valid if ret equals E_LEADER_CHANGED. - 2: common.HostAddr leader, + 2: common.HostAddr leader, 3: map(cpp.template = "std::unordered_map") users, } @@ -401,7 +402,7 @@ struct ListRolesReq { struct ListRolesResp { 1: ErrorCode code, // Valid if ret equals E_LEADER_CHANGED. - 2: common.HostAddr leader, + 2: common.HostAddr leader, 3: list roles, } diff --git a/src/meta/MetaServiceUtils.cpp b/src/meta/MetaServiceUtils.cpp index 2ed8292d164..ded55153426 100644 --- a/src/meta/MetaServiceUtils.cpp +++ b/src/meta/MetaServiceUtils.cpp @@ -270,10 +270,11 @@ std::string MetaServiceUtils::assembleSegmentKey(const std::string& segment, } cpp2::ErrorCode MetaServiceUtils::alterColumnDefs(std::vector& cols, + nebula::cpp2::SchemaProp& prop, const nebula::cpp2::ColumnDef col, const cpp2::AlterSchemaOp op) { switch (op) { - case cpp2::AlterSchemaOp::ADD : + case cpp2::AlterSchemaOp::ADD: { for (auto it = cols.begin(); it != cols.end(); ++it) { if (it->get_name() == col.get_name()) { @@ -284,7 +285,7 @@ cpp2::ErrorCode MetaServiceUtils::alterColumnDefs(std::vectorget_name()) { @@ -294,12 +295,21 @@ cpp2::ErrorCode MetaServiceUtils::alterColumnDefs(std::vectorget_name()) { - cols.erase(it); - return cpp2::ErrorCode::SUCCEEDED; + if (colName == it->get_name()) { + // Check if there is a TTL on the column to be deleted + if (!prop.get_ttl_col() || + (prop.get_ttl_col() && (*prop.get_ttl_col() != colName))) { + cols.erase(it); + return cpp2::ErrorCode::SUCCEEDED; + } else { + LOG(WARNING) << "Column can't be dropped, a TTL attribute on it : " + << colName; + return cpp2::ErrorCode::E_NOT_DROP; + } } } break; @@ -311,6 +321,47 @@ cpp2::ErrorCode MetaServiceUtils::alterColumnDefs(std::vector& cols, + nebula::cpp2::SchemaProp& schemaProp, + nebula::cpp2::SchemaProp alterSchemaProp) { + if (alterSchemaProp.__isset.ttl_duration) { + // Graph check <=0 to = 0 + schemaProp.set_ttl_duration(*alterSchemaProp.get_ttl_duration()); + } + if (alterSchemaProp.__isset.ttl_col) { + auto ttlCol = *alterSchemaProp.get_ttl_col(); + auto existed = false; + for (auto& col : cols) { + if (col.get_name() == ttlCol) { + // Only integer and timestamp columns can be used as ttl_col + if (col.type.type != nebula::cpp2::SupportedType::INT && + col.type.type != nebula::cpp2::SupportedType::TIMESTAMP) { + LOG(WARNING) << "TTL column type illegal"; + return cpp2::ErrorCode::E_UNSUPPORTED; + } + existed = true; + schemaProp.set_ttl_col(ttlCol); + break; + } + } + + if (!existed) { + LOG(WARNING) << "TTL column not found : " << ttlCol; + return cpp2::ErrorCode::E_NOT_FOUND; + } + } + + // Disable implicit TTL mode + if ((schemaProp.get_ttl_duration() && (*schemaProp.get_ttl_duration() != 0)) && + (!schemaProp.get_ttl_col() || (schemaProp.get_ttl_col() && + schemaProp.get_ttl_col()->empty()))) { + LOG(WARNING) << "Implicit ttl_col not support"; + return cpp2::ErrorCode::E_UNSUPPORTED; + } + + return cpp2::ErrorCode::SUCCEEDED; +} + std::string MetaServiceUtils::indexUserKey(const std::string& account) { std::string key; EntryType type = EntryType::USER; diff --git a/src/meta/MetaServiceUtils.h b/src/meta/MetaServiceUtils.h index fc1bf664770..27baa51dc5d 100644 --- a/src/meta/MetaServiceUtils.h +++ b/src/meta/MetaServiceUtils.h @@ -8,6 +8,7 @@ #define META_METAUTILS_H_ #include "base/Base.h" +#include "base/Status.h" #include "interface/gen-cpp2/meta_types.h" namespace nebula { @@ -87,9 +88,14 @@ class MetaServiceUtils final { static std::string assembleSegmentKey(const std::string& segment, const std::string& key); static cpp2::ErrorCode alterColumnDefs(std::vector& cols, + nebula::cpp2::SchemaProp& prop, const nebula::cpp2::ColumnDef col, const cpp2::AlterSchemaOp op); + static cpp2::ErrorCode alterSchemaProp(std::vector& cols, + nebula::cpp2::SchemaProp& schemaProp, + nebula::cpp2::SchemaProp alterSchemaProp); + static std::string indexUserKey(const std::string& account); static std::string userKey(UserID userId); diff --git a/src/meta/NebulaSchemaProvider.cpp b/src/meta/NebulaSchemaProvider.cpp index dd21426f483..5b51ea5156d 100644 --- a/src/meta/NebulaSchemaProvider.cpp +++ b/src/meta/NebulaSchemaProvider.cpp @@ -83,6 +83,14 @@ void NebulaSchemaProvider::addField(folly::StringPiece name, static_cast(fields_.size() - 1)); } +void NebulaSchemaProvider::setProp(nebula::cpp2::SchemaProp schemaProp) { + schemaProp_ = std::move(schemaProp); +} + +const nebula::cpp2::SchemaProp NebulaSchemaProvider::getProp() const { + return schemaProp_; +} + } // namespace meta } // namespace nebula diff --git a/src/meta/NebulaSchemaProvider.h b/src/meta/NebulaSchemaProvider.h index c264bfdcc3e..f6858b3dda3 100644 --- a/src/meta/NebulaSchemaProvider.h +++ b/src/meta/NebulaSchemaProvider.h @@ -56,6 +56,10 @@ class NebulaSchemaProvider : public SchemaProviderIf { void addField(folly::StringPiece name, nebula::cpp2::ValueType&& type); + void setProp(nebula::cpp2::SchemaProp schemaProp); + + const nebula::cpp2::SchemaProp getProp() const; + protected: NebulaSchemaProvider() = default; @@ -63,8 +67,9 @@ class NebulaSchemaProvider : public SchemaProviderIf { SchemaVer ver_{-1}; // fieldname -> index - std::unordered_map fieldNameIndex_; + std::unordered_map fieldNameIndex_; std::vector> fields_; + nebula::cpp2::SchemaProp schemaProp_; }; } // namespace meta diff --git a/src/meta/client/MetaClient.cpp b/src/meta/client/MetaClient.cpp index 2abad555996..2e9fe2feaaa 100644 --- a/src/meta/client/MetaClient.cpp +++ b/src/meta/client/MetaClient.cpp @@ -161,6 +161,8 @@ bool MetaClient::loadSchemas(GraphSpaceID spaceId, for (auto colIt : tagIt.schema.get_columns()) { schema->addField(colIt.name, std::move(colIt.type)); } + // handle schema property + schema->setProp(tagIt.schema.get_schema_prop()); tagIdSchemas.emplace(std::make_pair(tagIt.tag_id, tagIt.version), schema); tagNameIdMap.emplace(std::make_pair(spaceId, tagIt.tag_name), tagIt.tag_id); // get the latest tag version @@ -181,6 +183,8 @@ bool MetaClient::loadSchemas(GraphSpaceID spaceId, for (auto colIt : edgeIt.schema.get_columns()) { schema->addField(colIt.name, std::move(colIt.type)); } + // handle shcem property + schema->setProp(edgeIt.schema.get_schema_prop()); edgeTypeSchemas.emplace(std::make_pair(edgeIt.edge_type, edgeIt.version), schema); edgeNameTypeMap.emplace(std::make_pair(spaceId, edgeIt.edge_name), edgeIt.edge_type); // get the latest edge version @@ -748,11 +752,13 @@ MetaClient::createTagSchema(GraphSpaceID spaceId, std::string name, nebula::cpp2 folly::Future> MetaClient::alterTagSchema(GraphSpaceID spaceId, std::string name, - std::vector items) { + std::vector items, + nebula::cpp2::SchemaProp schemaProp) { cpp2::AlterTagReq req; req.set_space_id(std::move(spaceId)); req.set_tag_name(std::move(name)); req.set_tag_items(std::move(items)); + req.set_schema_prop(std::move(schemaProp)); return getResponse(std::move(req), [] (auto client, auto request) { return client->future_alterTag(request); @@ -818,11 +824,14 @@ MetaClient::createEdgeSchema(GraphSpaceID spaceId, std::string name, nebula::cpp folly::Future> MetaClient::alterEdgeSchema(GraphSpaceID spaceId, std::string name, - std::vector items) { + std::vector items, + nebula::cpp2::SchemaProp schemaProp) { cpp2::AlterEdgeReq req; req.set_space_id(std::move(spaceId)); req.set_edge_name(std::move(name)); req.set_edge_items(std::move(items)); + req.set_schema_prop(std::move(schemaProp)); + return getResponse(std::move(req), [] (auto client, auto request) { return client->future_alterEdge(request); }, [] (cpp2::ExecResp&& resp) -> bool { diff --git a/src/meta/client/MetaClient.h b/src/meta/client/MetaClient.h index 646a673d90b..bafcc713d8b 100644 --- a/src/meta/client/MetaClient.h +++ b/src/meta/client/MetaClient.h @@ -107,7 +107,8 @@ class MetaClient { folly::Future> alterTagSchema(GraphSpaceID spaceId, std::string name, - std::vector items); + std::vector items, + nebula::cpp2::SchemaProp schemaProp); folly::Future>> listTagSchemas(GraphSpaceID spaceId); @@ -125,7 +126,8 @@ class MetaClient { folly::Future> alterEdgeSchema(GraphSpaceID spaceId, std::string name, - std::vector items); + std::vector items, + nebula::cpp2::SchemaProp schemaProp); folly::Future>> listEdgeSchemas(GraphSpaceID spaceId); diff --git a/src/meta/processors/BaseProcessor.h b/src/meta/processors/BaseProcessor.h index 0835663112b..1ed61ef49bd 100644 --- a/src/meta/processors/BaseProcessor.h +++ b/src/meta/processors/BaseProcessor.h @@ -59,7 +59,7 @@ GENERATE_LOCK(user); } /** - * Check segemnt is consist of numbers and letters and should not empty. + * Check segment is consist of numbers and letters and should not empty. * */ #define CHECK_SEGMENT(segment) \ if (!MetaCommon::checkSegment(segment)) { \ diff --git a/src/meta/processors/schemaMan/AlterEdgeProcessor.cpp b/src/meta/processors/schemaMan/AlterEdgeProcessor.cpp index ef7a5e1af92..f328a1f094a 100644 --- a/src/meta/processors/schemaMan/AlterEdgeProcessor.cpp +++ b/src/meta/processors/schemaMan/AlterEdgeProcessor.cpp @@ -38,20 +38,37 @@ void AlterEdgeProcessor::process(const cpp2::AlterEdgeReq& req) { auto version = MetaServiceUtils::parseEdgeVersion(iter->key()) + 1; auto schema = MetaServiceUtils::parseSchema(iter->val()); auto columns = schema.get_columns(); + auto prop = schema.get_schema_prop(); + + // Update schema column auto& edgeItems = req.get_edge_items(); for (auto& edgeItem : edgeItems) { auto& cols = edgeItem.get_schema().get_columns(); for (auto& col : cols) { - auto retCode = MetaServiceUtils::alterColumnDefs(columns, col, edgeItem.op); + auto retCode = MetaServiceUtils::alterColumnDefs(columns, prop, col, edgeItem.op); if (retCode != cpp2::ErrorCode::SUCCEEDED) { - LOG(WARNING) << "Alter edge error " << static_cast(retCode); + LOG(WARNING) << "Alter edge column error " << static_cast(retCode); resp_.set_code(retCode); onFinished(); return; } } } + + // Update schema property + auto& alterSchemaProp = req.get_schema_prop(); + auto retCode = MetaServiceUtils::alterSchemaProp(columns, prop, std::move(alterSchemaProp)); + + if (retCode != cpp2::ErrorCode::SUCCEEDED) { + LOG(WARNING) << "Alter edge property error " << static_cast(retCode); + resp_.set_code(retCode); + onFinished(); + return; + } + schema.set_columns(std::move(columns)); + schema.set_schema_prop(std::move(prop)); + std::vector data; LOG(INFO) << "Alter edge " << req.get_edge_name() << ", edgeTye " << edgeType; data.emplace_back(MetaServiceUtils::schemaEdgeKey(req.get_space_id(), edgeType, version), diff --git a/src/meta/processors/schemaMan/AlterTagProcessor.cpp b/src/meta/processors/schemaMan/AlterTagProcessor.cpp index 407346991be..0e6c0ed5eaa 100644 --- a/src/meta/processors/schemaMan/AlterTagProcessor.cpp +++ b/src/meta/processors/schemaMan/AlterTagProcessor.cpp @@ -38,20 +38,37 @@ void AlterTagProcessor::process(const cpp2::AlterTagReq& req) { auto version = MetaServiceUtils::parseTagVersion(iter->key()) + 1; auto schema = MetaServiceUtils::parseSchema(iter->val()); auto columns = schema.get_columns(); + auto prop = schema.get_schema_prop(); + + // Update schema column auto& tagItems = req.get_tag_items(); for (auto& tagItem : tagItems) { auto& cols = tagItem.get_schema().get_columns(); for (auto& col : cols) { - auto retCode = MetaServiceUtils::alterColumnDefs(columns, col, tagItem.op); + auto retCode = MetaServiceUtils::alterColumnDefs(columns, prop, col, tagItem.op); if (retCode != cpp2::ErrorCode::SUCCEEDED) { - LOG(WARNING) << "Alter tag error " << static_cast(retCode); + LOG(WARNING) << "Alter tag column error " << static_cast(retCode); resp_.set_code(retCode); onFinished(); return; } } } + + // Update schema property + auto& alterSchemaProp = req.get_schema_prop(); + auto retCode = MetaServiceUtils::alterSchemaProp(columns, prop, std::move(alterSchemaProp)); + + if (retCode != cpp2::ErrorCode::SUCCEEDED) { + LOG(WARNING) << "Alter tag property error " << static_cast(retCode); + resp_.set_code(retCode); + onFinished(); + return; + } + schema.set_columns(std::move(columns)); + schema.set_schema_prop(std::move(prop)); + std::vector data; LOG(INFO) << "Alter Tag " << req.get_tag_name() << ", tagId " << tagId; data.emplace_back(MetaServiceUtils::schemaTagKey(req.get_space_id(), tagId, version), diff --git a/src/meta/test/ProcessorTest.cpp b/src/meta/test/ProcessorTest.cpp index eb5113ecc35..55e8db8880f 100644 --- a/src/meta/test/ProcessorTest.cpp +++ b/src/meta/test/ProcessorTest.cpp @@ -279,9 +279,9 @@ TEST(ProcessorTest, CreateTagTest) { { cpp2::SpaceProperties properties; - properties.set_space_name("default_space"); + properties.set_space_name("first_space"); properties.set_partition_num(9); - properties.set_replica_factor(3); + properties.set_replica_factor(1); cpp2::CreateSpaceReq req; req.set_properties(std::move(properties)); @@ -292,7 +292,21 @@ TEST(ProcessorTest, CreateTagTest) { ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); ASSERT_EQ(1, resp.get_id().get_space_id()); } + { + cpp2::SpaceProperties properties; + properties.set_space_name("second_space"); + properties.set_partition_num(9); + properties.set_replica_factor(1); + cpp2::CreateSpaceReq req; + req.set_properties(std::move(properties)); + auto* processor = CreateSpaceProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); + ASSERT_EQ(2, resp.get_id().get_space_id()); + } nebula::cpp2::Schema schema; decltype(schema.columns) cols; cols.emplace_back(TestUtils::columnDef(0, SupportedType::INT)); @@ -311,6 +325,20 @@ TEST(ProcessorTest, CreateTagTest) { ASSERT_EQ(cpp2::ErrorCode::E_NOT_FOUND, resp.code); } { + // Succeeded + cpp2::CreateTagReq req; + req.set_space_id(1); + req.set_tag_name("default_tag"); + req.set_schema(schema); + auto* processor = CreateTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); + ASSERT_EQ(3, resp.get_id().get_tag_id()); + } + { + // Existed cpp2::CreateTagReq req; req.set_space_id(1); req.set_tag_name("default_tag"); @@ -319,8 +347,39 @@ TEST(ProcessorTest, CreateTagTest) { auto f = processor->getFuture(); processor->process(req); auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::E_EXISTED, resp.code); + } + { + // Create same name tag in diff spaces + cpp2::CreateTagReq req; + req.set_space_id(2); + req.set_tag_name("default_tag"); + req.set_schema(schema); + auto* processor = CreateTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); + ASSERT_EQ(4, resp.get_id().get_tag_id()); + } + + // Set schema ttl property + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + schemaProp.set_ttl_col("col_0"); + schema.set_schema_prop(std::move(schemaProp)); + { + // Tag with TTL + cpp2::CreateTagReq req; + req.set_space_id(1); + req.set_tag_name("tag_ttl"); + req.set_schema(schema); + auto* processor = CreateTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_EQ(2, resp.get_id().get_tag_id()); + ASSERT_EQ(5, resp.get_id().get_tag_id()); } } @@ -390,7 +449,7 @@ TEST(ProcessorTest, CreateEdgeTest) { processor->process(req); auto resp = std::move(f).get(); ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_NE(0, resp.get_id().get_edge_type()); + ASSERT_EQ(3, resp.get_id().get_edge_type()); } { // Existed @@ -415,7 +474,26 @@ TEST(ProcessorTest, CreateEdgeTest) { processor->process(req); auto resp = std::move(f).get(); ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_NE(0, resp.get_id().get_edge_type()); + ASSERT_EQ(4, resp.get_id().get_edge_type()); + } + + // Set schema ttl property + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + schemaProp.set_ttl_col("col_0"); + schema.set_schema_prop(std::move(schemaProp)); + { + // Edge with TTL + cpp2::CreateEdgeReq req; + req.set_space_id(1); + req.set_edge_name("edge_ttl"); + req.set_schema(schema); + auto* processor = CreateEdgeProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); + ASSERT_EQ(5, resp.get_id().get_edge_type()); } } @@ -716,7 +794,29 @@ TEST(ProcessorTest, DropTagTest) { ASSERT_TRUE(TestUtils::assembleSpace(kv.get(), 1)); TestUtils::mockTag(kv.get(), 1); - // Remove tag processor test + // Space not exist + { + cpp2::DropTagReq req; + req.set_space_id(0); + req.set_tag_name("tag_0"); + auto* processor = DropTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::E_NOT_FOUND, resp.get_code()); + } + // Tag not exist + { + cpp2::DropTagReq req; + req.set_space_id(1); + req.set_tag_name("tag_no"); + auto* processor = DropTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::E_NOT_FOUND, resp.get_code()); + } + // Succeeded { cpp2::DropTagReq req; req.set_space_id(1); @@ -733,7 +833,7 @@ TEST(ProcessorTest, DropTagTest) { std::string tagVal; kvstore::ResultCode ret; std::unique_ptr iter; - ret = kv.get()->get(0, 0, std::move(MetaServiceUtils::indexTagKey(1, "tag_1")), + ret = kv.get()->get(0, 0, std::move(MetaServiceUtils::indexTagKey(1, "tag_0")), &tagVal); ASSERT_EQ(kvstore::ResultCode::ERR_KEY_NOT_FOUND, ret); std::string tagPrefix = "__tags__"; @@ -783,13 +883,12 @@ TEST(ProcessorTest, DropEdgeTest) { auto resp = std::move(f).get(); ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); } - // Check edge data has been deleted. { std::string edgeVal; kvstore::ResultCode ret; std::unique_ptr iter; - ret = kv.get()->get(0, 0, std::move(MetaServiceUtils::indexEdgeKey(1, "edge_1")), + ret = kv.get()->get(0, 0, std::move(MetaServiceUtils::indexEdgeKey(1, "edge_0")), &edgeVal); ASSERT_EQ(kvstore::ResultCode::ERR_KEY_NOT_FOUND, ret); std::string edgePrefix = "__edges__"; @@ -805,8 +904,7 @@ TEST(ProcessorTest, AlterTagTest) { auto kv = TestUtils::initKV(rootPath.path()); ASSERT_TRUE(TestUtils::assembleSpace(kv.get(), 1)); TestUtils::mockTag(kv.get(), 1); - - // Alter tag processor test + // Alter tag options test { cpp2::AlterTagReq req; std::vector items; @@ -817,12 +915,12 @@ TEST(ProcessorTest, AlterTagTest) { column.type.type = i < 1 ? SupportedType::INT : SupportedType::STRING; addSch.columns.emplace_back(std::move(column)); } - nebula::cpp2::Schema setSch; + nebula::cpp2::Schema changeSch; for (auto i = 0; i < 2; i++) { nebula::cpp2::ColumnDef column; column.name = folly::stringPrintf("tag_%d_col_%d", 0, i); column.type.type = i < 1 ? SupportedType::BOOL : SupportedType::DOUBLE; - setSch.columns.emplace_back(std::move(column)); + changeSch.columns.emplace_back(std::move(column)); } nebula::cpp2::Schema dropSch; nebula::cpp2::ColumnDef column; @@ -830,7 +928,7 @@ TEST(ProcessorTest, AlterTagTest) { dropSch.columns.emplace_back(std::move(column)); items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::ADD, std::move(addSch)); - items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::CHANGE, std::move(setSch)); + items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::CHANGE, std::move(changeSch)); items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::DROP, std::move(dropSch)); req.set_space_id(1); req.set_tag_name("tag_0"); @@ -873,9 +971,109 @@ TEST(ProcessorTest, AlterTagTest) { column.name = "tag_0_col_11"; column.type.type = SupportedType::STRING; cols.emplace_back(std::move(column)); + schema.set_columns(std::move(cols)); EXPECT_EQ(schema, tag.get_schema()); } + // Alter tag with ttl + { + // Only set ttl_duration + cpp2::AlterTagReq req; + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + + req.set_space_id(1); + req.set_tag_name("tag_0"); + req.set_schema_prop(std::move(schemaProp)); + auto* processor = AlterTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + } + { + // Succeeded + cpp2::AlterTagReq req; + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + schemaProp.set_ttl_col("tag_0_col_10"); + + req.set_space_id(1); + req.set_tag_name("tag_0"); + req.set_schema_prop(std::move(schemaProp)); + auto* processor = AlterTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + } + // Verify alter result. + { + cpp2::ListTagsReq req; + req.set_space_id(1); + auto* processor = ListTagsProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + auto tags = resp.get_tags(); + ASSERT_EQ(3, tags.size()); + // TagItems in vector are unordered.So need to get the latest one by comparing the versions. + auto tag = tags[0].version > tags[1].version ? tags[0] : tags[1]; + tag = tag.version > tags[2].version ? tag : tags[2]; + + EXPECT_EQ(0, tag.get_tag_id()); + EXPECT_EQ(folly::stringPrintf("tag_%d", 0), tag.get_tag_name()); + EXPECT_EQ(2, tag.version); + + nebula::cpp2::Schema schema; + decltype(schema.columns) cols; + + nebula::cpp2::ColumnDef column; + column.name = "tag_0_col_1"; + column.type.type = SupportedType::DOUBLE; + cols.emplace_back(std::move(column)); + + column.name = "tag_0_col_10"; + column.type.type = SupportedType::INT; + cols.emplace_back(std::move(column)); + + column.name = "tag_0_col_11"; + column.type.type = SupportedType::STRING; + cols.emplace_back(std::move(column)); + + schema.set_columns(std::move(cols)); + + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + schemaProp.set_ttl_col("tag_0_col_10"); + schema.set_schema_prop(std::move(schemaProp)); + EXPECT_EQ(schema.get_columns(), tag.get_schema().get_columns()); + EXPECT_EQ(*schema.get_schema_prop().get_ttl_duration(), + *tag.get_schema().get_schema_prop().get_ttl_duration()); + EXPECT_EQ(*schema.get_schema_prop().get_ttl_col(), + *tag.get_schema().get_schema_prop().get_ttl_col()); + } + + { + // Drop ttl_col column, failed + cpp2::AlterTagReq req; + std::vector items; + nebula::cpp2::Schema dropSch; + nebula::cpp2::ColumnDef column; + column.name = folly::stringPrintf("tag_%d_col_%d", 0, 10); + dropSch.columns.emplace_back(std::move(column)); + + items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::DROP, std::move(dropSch)); + req.set_space_id(1); + req.set_tag_name("tag_0"); + req.set_tag_items(items); + auto* processor = AlterTagProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + } // Verify ErrorCode of add { cpp2::AlterTagReq req; @@ -898,19 +1096,19 @@ TEST(ProcessorTest, AlterTagTest) { auto resp = std::move(f).get(); ASSERT_EQ(cpp2::ErrorCode::E_EXISTED, resp.get_code()); } - // Verify ErrorCode of set + // Verify ErrorCode of change { cpp2::AlterTagReq req; std::vector items; - nebula::cpp2::Schema addSch; + nebula::cpp2::Schema changeSch; nebula::cpp2::ColumnDef column; column.name = "tag_0_col_2"; column.type.type = SupportedType::INT; - addSch.columns.emplace_back(std::move(column)); - auto addItem = cpp2::AlterSchemaItem(FRAGILE, - cpp2::AlterSchemaOp::CHANGE, - std::move(addSch)); - items.emplace_back(std::move(addItem)); + changeSch.columns.emplace_back(std::move(column)); + auto changeItem = cpp2::AlterSchemaItem(FRAGILE, + cpp2::AlterSchemaOp::CHANGE, + std::move(changeSch)); + items.emplace_back(std::move(changeItem)); req.set_space_id(1); req.set_tag_name("tag_0"); req.set_tag_items(items); @@ -924,12 +1122,12 @@ TEST(ProcessorTest, AlterTagTest) { { cpp2::AlterTagReq req; std::vector items; - nebula::cpp2::Schema addSch; + nebula::cpp2::Schema dropSch; nebula::cpp2::ColumnDef column; - column.name = "tag_0_col_2"; + column.name = "tag_0_col_0"; column.type.type = SupportedType::INT; - addSch.columns.emplace_back(std::move(column)); - items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::DROP, std::move(addSch)); + dropSch.columns.emplace_back(std::move(column)); + items.emplace_back(FRAGILE, cpp2::AlterSchemaOp::DROP, std::move(dropSch)); req.set_space_id(1); req.set_tag_name("tag_0"); req.set_tag_items(items); @@ -998,10 +1196,10 @@ TEST(ProcessorTest, AlterEdgeTest) { column.name = folly::stringPrintf("edge_%d_col_%d", 0, 1); addSch.columns.emplace_back(std::move(column)); - auto dropItem = cpp2::AlterSchemaItem(FRAGILE, - cpp2::AlterSchemaOp::ADD, - std::move(addSch)); - items.emplace_back(std::move(dropItem)); + auto addItem = cpp2::AlterSchemaItem(FRAGILE, + cpp2::AlterSchemaOp::ADD, + std::move(addSch)); + items.emplace_back(std::move(addItem)); req.set_space_id(1); req.set_edge_name("edge_0"); req.set_edge_items(items); @@ -1021,12 +1219,12 @@ TEST(ProcessorTest, AlterEdgeTest) { column.type.type = i < 1 ? SupportedType::INT : SupportedType::STRING; addSch.columns.emplace_back(std::move(column)); } - nebula::cpp2::Schema setSch; + nebula::cpp2::Schema changeSch; for (auto i = 0; i < 2; i++) { nebula::cpp2::ColumnDef column; column.name = folly::stringPrintf("edge_%d_col_%d", 0, i); column.type.type = i < 1 ? SupportedType::BOOL : SupportedType::DOUBLE; - setSch.columns.emplace_back(std::move(column)); + changeSch.columns.emplace_back(std::move(column)); } nebula::cpp2::Schema dropSch; nebula::cpp2::ColumnDef column; @@ -1036,14 +1234,14 @@ TEST(ProcessorTest, AlterEdgeTest) { auto addItem = cpp2::AlterSchemaItem(FRAGILE, cpp2::AlterSchemaOp::ADD, std::move(addSch)); - auto setItem = cpp2::AlterSchemaItem(FRAGILE, - cpp2::AlterSchemaOp::CHANGE, - std::move(setSch)); + auto changeItem = cpp2::AlterSchemaItem(FRAGILE, + cpp2::AlterSchemaOp::CHANGE, + std::move(changeSch)); auto dropItem = cpp2::AlterSchemaItem(FRAGILE, cpp2::AlterSchemaOp::DROP, std::move(dropSch)); items.emplace_back(std::move(addItem)); - items.emplace_back(std::move(setItem)); + items.emplace_back(std::move(changeItem)); items.emplace_back(std::move(dropItem)); req.set_space_id(1); req.set_edge_name("edge_0"); @@ -1089,6 +1287,115 @@ TEST(ProcessorTest, AlterEdgeTest) { schema.set_columns(std::move(cols)); EXPECT_EQ(schema, edge.get_schema()); } + + // Alter edge with ttl + { + // only set ttl_duration, failed + cpp2::AlterEdgeReq req; + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + + req.set_space_id(1); + req.set_edge_name("edge_0"); + req.set_schema_prop(std::move(schemaProp)); + auto* processor = AlterEdgeProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + } + { + // Succeed + cpp2::AlterEdgeReq req; + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + schemaProp.set_ttl_col("edge_0_col_10"); + + req.set_space_id(1); + req.set_edge_name("edge_0"); + req.set_schema_prop(std::move(schemaProp)); + auto* processor = AlterEdgeProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + } + // Verify alter result. + { + cpp2::ListEdgesReq req; + req.set_space_id(1); + auto* processor = ListEdgesProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + auto edges = resp.get_edges(); + ASSERT_EQ(5, edges.size()); + // EdgeItems in vector are unordered.So get the latest one by comparing the versions. + int version = 0; + int max_index = 0; + for (uint32_t i = 0; i < edges.size(); i++) { + if (edges[i].version > version) { + max_index = i; + version = edges[i].version; + } + } + auto edge = edges[max_index]; + + EXPECT_EQ(0, edge.get_edge_type()); + EXPECT_EQ(folly::stringPrintf("edge_%d", 0), edge.get_edge_name()); + EXPECT_EQ(4, edge.version); + + nebula::cpp2::Schema schema; + decltype(schema.columns) cols; + + nebula::cpp2::ColumnDef column; + column.name = "edge_0_col_1"; + column.type.type = SupportedType::DOUBLE; + cols.emplace_back(std::move(column)); + + column.name = "edge_0_col_10"; + column.type.type = SupportedType::INT; + cols.emplace_back(std::move(column)); + + column.name = "edge_0_col_11"; + column.type.type = SupportedType::STRING; + cols.emplace_back(std::move(column)); + + schema.set_columns(std::move(cols)); + + nebula::cpp2::SchemaProp schemaProp; + schemaProp.set_ttl_duration(100); + schemaProp.set_ttl_col("edge_0_col_10"); + schema.set_schema_prop(std::move(schemaProp)); + EXPECT_EQ(schema.get_columns(), edge.get_schema().get_columns()); + EXPECT_EQ(*schema.get_schema_prop().get_ttl_duration(), + *edge.get_schema().get_schema_prop().get_ttl_duration()); + EXPECT_EQ(*schema.get_schema_prop().get_ttl_col(), + *edge.get_schema().get_schema_prop().get_ttl_col()); + } + { + // Drop ttl_col column, failed + cpp2::AlterEdgeReq req; + std::vector items; + nebula::cpp2::Schema dropSch; + nebula::cpp2::ColumnDef column; + column.name = folly::stringPrintf("edge_%d_col_%d", 0, 10); + dropSch.columns.emplace_back(std::move(column)); + + auto dropItem = cpp2::AlterSchemaItem(FRAGILE, + cpp2::AlterSchemaOp::DROP, + std::move(dropSch)); + items.emplace_back(std::move(dropItem)); + req.set_space_id(1); + req.set_edge_name("edge_0"); + req.set_edge_items(items); + auto* processor = AlterEdgeProcessor::instance(kv.get()); + auto f = processor->getFuture(); + processor->process(req); + auto resp = std::move(f).get(); + ASSERT_NE(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); + } // Verify ErrorCode of add { cpp2::AlterEdgeReq req; @@ -1111,19 +1418,19 @@ TEST(ProcessorTest, AlterEdgeTest) { auto resp = std::move(f).get(); ASSERT_EQ(cpp2::ErrorCode::E_EXISTED, resp.get_code()); } - // Verify ErrorCode of set + // Verify ErrorCode of change { cpp2::AlterEdgeReq req; std::vector items; - nebula::cpp2::Schema addSch; + nebula::cpp2::Schema changeSch; nebula::cpp2::ColumnDef column; column.name = "edge_0_col_2"; column.type.type = SupportedType::INT; - addSch.columns.emplace_back(std::move(column)); - auto addItem = cpp2::AlterSchemaItem(FRAGILE, - cpp2::AlterSchemaOp::CHANGE, - std::move(addSch)); - items.emplace_back(std::move(addItem)); + changeSch.columns.emplace_back(std::move(column)); + auto changeItem = cpp2::AlterSchemaItem(FRAGILE, + cpp2::AlterSchemaOp::CHANGE, + std::move(changeSch)); + items.emplace_back(std::move(changeItem)); req.set_space_id(1); req.set_edge_name("edge_0"); req.set_edge_items(items); @@ -1137,13 +1444,15 @@ TEST(ProcessorTest, AlterEdgeTest) { { cpp2::AlterEdgeReq req; std::vector items; - nebula::cpp2::Schema addSch; + nebula::cpp2::Schema dropSch; nebula::cpp2::ColumnDef column; column.name = "edge_0_col_2"; column.type.type = SupportedType::INT; - addSch.columns.emplace_back(std::move(column)); - auto addItem = cpp2::AlterSchemaItem(FRAGILE, cpp2::AlterSchemaOp::DROP, std::move(addSch)); - items.emplace_back(addItem); + dropSch.columns.emplace_back(std::move(column)); + auto dropItem = cpp2::AlterSchemaItem(FRAGILE, + cpp2::AlterSchemaOp::DROP, + std::move(dropSch)); + items.emplace_back(dropItem); req.set_space_id(1); req.set_edge_name("edge_0"); req.set_edge_items(items); @@ -1155,115 +1464,6 @@ TEST(ProcessorTest, AlterEdgeTest) { } } - -TEST(ProcessorTest, SameNameTagsTest) { - fs::TempDir rootPath("/tmp/SameNameTagsTest.XXXXXX"); - auto kv = TestUtils::initKV(rootPath.path()); - TestUtils::createSomeHosts(kv.get()); - - { - cpp2::SpaceProperties properties; - properties.set_space_name("default_space"); - properties.set_partition_num(9); - properties.set_replica_factor(3); - cpp2::CreateSpaceReq req; - req.set_properties(std::move(properties)); - auto* processor = CreateSpaceProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_EQ(1, resp.get_id().get_space_id()); - } - { - cpp2::SpaceProperties properties; - properties.set_space_name("second_space"); - properties.set_partition_num(9); - properties.set_replica_factor(1); - cpp2::CreateSpaceReq req; - req.set_properties(std::move(properties)); - auto* processor = CreateSpaceProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_EQ(2, resp.get_id().get_space_id()); - } - - // Add same tag name in different space - nebula::cpp2::Schema schema; - decltype(schema.columns) cols; - cols.emplace_back(TestUtils::columnDef(0, SupportedType::INT)); - cols.emplace_back(TestUtils::columnDef(1, SupportedType::FLOAT)); - cols.emplace_back(TestUtils::columnDef(2, SupportedType::STRING)); - schema.set_columns(std::move(cols)); - { - cpp2::CreateTagReq req; - req.set_space_id(1); - req.set_tag_name("default_tag"); - req.set_schema(schema); - auto* processor = CreateTagProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_EQ(3, resp.get_id().get_tag_id()); - } - { - cpp2::CreateTagReq req; - req.set_space_id(2); - req.set_tag_name("default_tag"); - req.set_schema(schema); - auto* processor = CreateTagProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.code); - ASSERT_EQ(4, resp.get_id().get_tag_id()); - } - - // Remove Test - { - cpp2::DropTagReq req; - req.set_space_id(1); - req.set_tag_name("default_tag"); - auto* processor = DropTagProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); - } - - // List Test - { - cpp2::ListTagsReq req; - req.set_space_id(1); - auto* processor = ListTagsProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - decltype(resp.tags) tags; - tags = resp.get_tags(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); - ASSERT_EQ(0, tags.size()); - } - { - cpp2::ListTagsReq req; - req.set_space_id(2); - auto* processor = ListTagsProcessor::instance(kv.get()); - auto f = processor->getFuture(); - processor->process(req); - auto resp = std::move(f).get(); - decltype(resp.tags) tags; - tags = resp.get_tags(); - ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, resp.get_code()); - ASSERT_EQ(1, tags.size()); - - ASSERT_EQ(4, tags[0].get_tag_id()); - ASSERT_EQ("default_tag", tags[0].get_tag_name()); - } -} - } // namespace meta } // namespace nebula diff --git a/src/parser/MaintainSentences.h b/src/parser/MaintainSentences.h index 148bf66f711..34a978c82e6 100644 --- a/src/parser/MaintainSentences.h +++ b/src/parser/MaintainSentences.h @@ -65,7 +65,7 @@ class SchemaPropItem final { enum PropType : uint8_t { TTL_DURATION, - TTL_COL, + TTL_COL }; SchemaPropItem(PropType op, int64_t val) { @@ -303,7 +303,7 @@ class AlterTagSentence final : public Sentence { return name_.get(); } - std::vector schemaOptList() const { + std::vector getSchemaOpts() const { return opts_->alterSchemaItems(); } @@ -335,7 +335,7 @@ class AlterEdgeSentence final : public Sentence { return name_.get(); } - std::vector schemaOptList() const { + std::vector getSchemaOpts() const { return opts_->alterSchemaItems(); } diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 6a70c59d95a..bd0b3dcbc25 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -537,6 +537,10 @@ create_schema_prop_list create_schema_prop_item : KW_TTL_DURATION ASSIGN INTEGER { + // Less than or equal to 0 means infinity, so less than 0 is equivalent to 0 + if ($3 < 0) { + $3 = 0; + } $$ = new SchemaPropItem(SchemaPropItem::TTL_DURATION, $3); } | KW_TTL_COL ASSIGN name_label { @@ -614,6 +618,10 @@ alter_schema_prop_list alter_schema_prop_item : KW_TTL_DURATION ASSIGN INTEGER { + // Less than or equal to 0 means infinity, so less than 0 is equivalent to 0 + if ($3 < 0) { + $3 = 0; + } $$ = new SchemaPropItem(SchemaPropItem::TTL_DURATION, $3); } | KW_TTL_COL ASSIGN name_label {