From ec05c1060337eb6dffade4918a9c993de7252855 Mon Sep 17 00:00:00 2001 From: Zhenzhen Zhao <229194950@qq.com> Date: Mon, 13 Dec 2021 05:42:18 +0000 Subject: [PATCH 1/3] feat(parser): create/drop function Bug: cannot parse "create function xxx from ...", check ParserTest.cpp#L400 --- .linters/cpp/checkKeyword.py | 1 + src/graph/service/PermissionCheck.cpp | 4 ++ src/graph/validator/MaintainValidator.cpp | 12 ++++++ src/graph/validator/Validator.cpp | 4 ++ src/parser/MaintainSentences.cpp | 18 ++++++++ src/parser/MaintainSentences.h | 51 +++++++++++++++++++++++ src/parser/Sentence.h | 3 ++ src/parser/parser.yy | 30 +++++++++++++ src/parser/scanner.lex | 13 ++++++ src/parser/test/ParserTest.cpp | 32 ++++++++++++++ src/parser/test/ScannerTest.cpp | 5 +++ 11 files changed, 173 insertions(+) diff --git a/.linters/cpp/checkKeyword.py b/.linters/cpp/checkKeyword.py index af8916cf1a9..8828b6c1e5e 100755 --- a/.linters/cpp/checkKeyword.py +++ b/.linters/cpp/checkKeyword.py @@ -61,6 +61,7 @@ 'KW_TIME', 'KW_DATETIME', 'KW_VID_SIZE', + 'KW_FUNCTION', 'KW_TAG', 'KW_TAGS', 'KW_UNION', diff --git a/src/graph/service/PermissionCheck.cpp b/src/graph/service/PermissionCheck.cpp index f23bac7386b..dc2a0288db7 100644 --- a/src/graph/service/PermissionCheck.cpp +++ b/src/graph/service/PermissionCheck.cpp @@ -26,6 +26,7 @@ namespace graph { * kInsertVertex, kUpdateVertex, kInsertEdge, * kUpdateEdge, kDeleteVertex, kDeleteEdges * Special operation : kShow, kChangePassword + * UDF : kCreateFunction, kAlterFunction, kDropFunction */ // static @@ -83,6 +84,9 @@ Status PermissionCheck::permissionCheck(ClientSession *session, case Sentence::Kind::kAlterEdge: case Sentence::Kind::kDropTag: case Sentence::Kind::kDropEdge: + case Sentence::Kind::kCreateFunction: + case Sentence::Kind::kAlterFunction: + case Sentence::Kind::kDropFunction: case Sentence::Kind::kCreateTagIndex: case Sentence::Kind::kCreateEdgeIndex: case Sentence::Kind::kCreateFTIndex: diff --git a/src/graph/validator/MaintainValidator.cpp b/src/graph/validator/MaintainValidator.cpp index 8fc51f5bd70..c55634c397d 100644 --- a/src/graph/validator/MaintainValidator.cpp +++ b/src/graph/validator/MaintainValidator.cpp @@ -139,6 +139,11 @@ static Status checkColName(const std::vector specs) { return Status::OK(); } +Status CreateFunctionValidator::validateImpl() { + // TODO(TripleZ): add create function logic + return Status::OK(); +} + Status CreateTagValidator::validateImpl() { createCtx_ = getContext(); auto sentence = static_cast(sentence_); @@ -269,6 +274,13 @@ Status ShowCreateEdgeValidator::toPlan() { return Status::OK(); } +Status DropFunctionValidator::validateImpl() { return Status::OK(); } + +Status DropFunctionValidator::toPlan() { + // TODO(TripleZ): add drop function logic + return Status::OK(); +} + Status DropTagValidator::validateImpl() { return Status::OK(); } Status DropTagValidator::toPlan() { diff --git a/src/graph/validator/Validator.cpp b/src/graph/validator/Validator.cpp index ef74a89127e..905ea788172 100644 --- a/src/graph/validator/Validator.cpp +++ b/src/graph/validator/Validator.cpp @@ -81,6 +81,8 @@ std::unique_ptr Validator::makeValidator(Sentence* sentence, QueryCon return std::make_unique(sentence, context); case Sentence::Kind::kCreateSpaceAs: return std::make_unique(sentence, context); + case Sentence::Kind::kCreateFunction: + return std::make_unique(sentence, context); case Sentence::Kind::kCreateTag: return std::make_unique(sentence, context); case Sentence::Kind::kCreateEdge: @@ -103,6 +105,8 @@ std::unique_ptr Validator::makeValidator(Sentence* sentence, QueryCon return std::make_unique(sentence, context); case Sentence::Kind::kDropSpace: return std::make_unique(sentence, context); + case Sentence::Kind::kDropFunction: + return std::make_unique(sentence, context); case Sentence::Kind::kDropTag: return std::make_unique(sentence, context); case Sentence::Kind::kDropEdge: diff --git a/src/parser/MaintainSentences.cpp b/src/parser/MaintainSentences.cpp index 81f4361a260..e474cbf2e43 100644 --- a/src/parser/MaintainSentences.cpp +++ b/src/parser/MaintainSentences.cpp @@ -91,6 +91,20 @@ std::string ColumnSpecificationList::toString() const { return buf; } +std::string CreateFunctionSentence::toString() const { + std::string buf; + buf.reserve(256); + buf += "CREATE FUNCTION "; + if (isIfNotExist()) { + buf += "IF NOT EXISTS "; + } + buf += "`"; + buf += *name_; + buf += "` "; + buf += funcSource_->toString(); + return buf; +} + std::string CreateTagSentence::toString() const { std::string buf; buf.reserve(256); @@ -224,6 +238,10 @@ std::string DescribeEdgeSentence::toString() const { return folly::stringPrintf("DESCRIBE EDGE %s", name_.get()->c_str()); } +std::string DropFunctionSentence::toString() const { + return folly::stringPrintf("DROP FUNCTION %s", name_.get()->c_str()); +} + std::string DropTagSentence::toString() const { return folly::stringPrintf("DROP TAG %s", name_.get()->c_str()); } diff --git a/src/parser/MaintainSentences.h b/src/parser/MaintainSentences.h index 16fb8ebd22f..2b51e8b2469 100644 --- a/src/parser/MaintainSentences.h +++ b/src/parser/MaintainSentences.h @@ -130,6 +130,20 @@ class ColumnSpecificationList final { std::vector> columns_; }; +class FunctionSource final { + public: + FunctionSource() = default; + FunctionSource(std::string type, std::string source): type_(type), source_(source) {} + + std::string toString() const { + return source_; + } + + private: + std::string type_; + std::string source_; +}; + class ColumnNameList final { public: ColumnNameList() = default; @@ -288,6 +302,28 @@ class CreateTagSentence final : public CreateSentence { std::unique_ptr schemaProps_; }; +class CreateFunctionSentence final : public CreateSentence { + public: + CreateFunctionSentence(std::string *name, + FunctionSource *funcSource, + bool ifNotExists) + : CreateSentence(ifNotExists) { + name_.reset(name); + funcSource_.reset(funcSource); + kind_ = Kind::kCreateFunction; + } + + std::string toString() const override; + + const std::string *name() const { return name_.get(); } + + FunctionSource* getFunctionSource() const { return funcSource_.get(); } + + private: + std::unique_ptr name_; + std::unique_ptr funcSource_; +}; + class CreateEdgeSentence final : public CreateSentence { public: CreateEdgeSentence(std::string *name, @@ -440,6 +476,21 @@ class DescribeEdgeSentence final : public Sentence { std::unique_ptr name_; }; +class DropFunctionSentence final : public DropSentence { + public: + explicit DropFunctionSentence(std::string *name, bool ifExists) : DropSentence(ifExists) { + name_.reset(name); + kind_ = Kind::kDropFunction; + } + + std::string toString() const override; + + const std::string *name() const { return name_.get(); } + + private: + std::unique_ptr name_; +}; + class DropTagSentence final : public DropSentence { public: explicit DropTagSentence(std::string *name, bool ifExists) : DropSentence(ifExists) { diff --git a/src/parser/Sentence.h b/src/parser/Sentence.h index 05552da6b89..949ebaca736 100644 --- a/src/parser/Sentence.h +++ b/src/parser/Sentence.h @@ -39,6 +39,9 @@ class Sentence { kAssignment, kCreateTag, kAlterTag, + kCreateFunction, + kAlterFunction, + kDropFunction, kCreateEdge, kAlterEdge, kDescribeTag, diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 6588ed35041..d41b1f8025e 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -105,6 +105,7 @@ static constexpr size_t kCommentLengthLimit = 256; nebula::AlterSchemaOptItem *alter_schema_opt_item; nebula::RoleTypeClause *role_type_clause; nebula::AclItemClause *acl_item_clause; + nebula::FunctionSource *function_source; nebula::SchemaPropList *create_schema_prop_list; nebula::SchemaPropItem *create_schema_prop_item; nebula::SchemaPropList *alter_schema_prop_list; @@ -201,6 +202,7 @@ static constexpr size_t kCommentLengthLimit = 256; %token KW_SESSIONS KW_SESSION %token KW_KILL KW_QUERY KW_QUERIES KW_TOP %token KW_GEOGRAPHY KW_POINT KW_LINESTRING KW_POLYGON +%token KW_FUNCTION /* symbols */ %token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE COMMA @@ -213,6 +215,7 @@ static constexpr size_t kCommentLengthLimit = 256; %token INTEGER %token DOUBLE %token STRING VARIABLE LABEL IPV4 +%token HTTP_URL WASM_BASE64 %type name_label unreserved_keyword predicate_name %type expression @@ -359,6 +362,10 @@ static constexpr size_t kCommentLengthLimit = 256; %type create_snapshot_sentence drop_snapshot_sentence %type add_listener_sentence remove_listener_sentence list_listener_sentence +%type create_function_sentence +%type create_function_from_vendor +%type drop_function_sentence + %type admin_job_sentence %type create_user_sentence alter_user_sentence drop_user_sentence change_password_sentence %type show_queries_sentence kill_query_sentence @@ -2195,6 +2202,27 @@ create_schema_prop_item } ; +create_function_from_vendor + : HTTP_URL { + $$ = new FunctionSource(std::string("HTTP"), *$1); + } + | WASM_BASE64 { + $$ = new FunctionSource(std::string("WASM"), *$1); + } + ; + +create_function_sentence + : KW_CREATE KW_FUNCTION opt_if_not_exists name_label KW_FROM create_function_from_vendor { + $$ = new CreateFunctionSentence($4, $6, $3); + } + ; + +drop_function_sentence + : KW_DROP KW_FUNCTION opt_if_exists name_label { + $$ = new DropFunctionSentence($4, $3); + } + ; + create_tag_sentence : KW_CREATE KW_TAG opt_if_not_exists name_label L_PAREN R_PAREN opt_create_schema_prop_list { if ($7 == nullptr) { @@ -3508,10 +3536,12 @@ maintain_sentence | drop_space_sentence { $$ = $1; } | create_tag_sentence { $$ = $1; } | create_edge_sentence { $$ = $1; } + | create_function_sentence { $$ = $1; } | alter_tag_sentence { $$ = $1; } | alter_edge_sentence { $$ = $1; } | describe_tag_sentence { $$ = $1; } | describe_edge_sentence { $$ = $1; } + | drop_function_sentence { $$ = $1; } | drop_tag_sentence { $$ = $1; } | drop_edge_sentence { $$ = $1; } | create_tag_index_sentence { $$ = $1; } diff --git a/src/parser/scanner.lex b/src/parser/scanner.lex index 6c316e4b2bf..566dadca8c1 100644 --- a/src/parser/scanner.lex +++ b/src/parser/scanner.lex @@ -45,6 +45,10 @@ IP_OCTET ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) +HTTP_URL (http:\/\/[a-zA-Z0-9\(\)@:%._\-\+~#=?&\/]+) +WASM_BASE64 (wasm:\/\/[A-Za-z0-9+\/=]+) +/* WASM_BASE64 (wasm:\/\/(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)) */ + %% /* Reserved keyword */ @@ -97,6 +101,7 @@ IP_OCTET ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) "DATE" { return TokenType::KW_DATE; } "TIME" { return TokenType::KW_TIME; } "DATETIME" { return TokenType::KW_DATETIME; } +"FUNCTION" { return TokenType::KW_FUNCTION; } "TAG" { return TokenType::KW_TAG; } "TAGS" { return TokenType::KW_TAGS; } "UNION" { return TokenType::KW_UNION; } @@ -331,6 +336,14 @@ IP_OCTET ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) } return TokenType::LABEL; } +{HTTP_URL} { + yylval->strval = new std::string(yytext, yyleng); + return TokenType::HTTP_URL; + } +{WASM_BASE64} { + yylval->strval = new std::string(yytext, yyleng); + return TokenType::WASM_BASE64; + } {IP_OCTET}(\.{IP_OCTET}){3} { yylval->strval = new std::string(yytext, yyleng); return TokenType::IPV4; diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index 29634fefabc..6c7c886c4d1 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -397,6 +397,38 @@ TEST_F(ParserTest, TagOperation) { } } +TEST_F(ParserTest, FunctionOperation) { + { + std::string query = "CREATE FUNCTION `f1 FROM wasm://d2FzbQo="; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + // { + // std::string query = + // "CREATE FUNCTION f1 FROM http://nebula-graph.io/remote/f1"; + // auto result = parse(query); + // ASSERT_TRUE(result.ok()) << result.status(); + // } + // { + // std::string query = + // "CREATE FUNCTION IF NOT EXISTS f1 FROM wasm://d2FzbQo="; + // auto result = parse(query); + // ASSERT_TRUE(result.ok()) << result.status(); + // } + // { + // std::string query = + // "CREATE FUNCTION IF NOT EXISTS f1 FROM http://nebula-graph.io/remote/f1"; + // auto result = parse(query); + // ASSERT_TRUE(result.ok()) << result.status(); + // } + // { + // std::string query = + // "DROP FUNCTION f1"; + // auto result = parse(query); + // ASSERT_TRUE(result.ok()) << result.status(); + // } +} + TEST_F(ParserTest, EdgeOperation) { { std::string query = diff --git a/src/parser/test/ScannerTest.cpp b/src/parser/test/ScannerTest.cpp index 9f1c155e868..5fee115d13c 100644 --- a/src/parser/test/ScannerTest.cpp +++ b/src/parser/test/ScannerTest.cpp @@ -500,6 +500,8 @@ TEST(Scanner, Basic) { CHECK_SEMANTIC_TYPE("TOP", TokenType::KW_TOP), CHECK_SEMANTIC_TYPE("Top", TokenType::KW_TOP), CHECK_SEMANTIC_TYPE("top", TokenType::KW_TOP), + CHECK_SEMANTIC_TYPE("FUNCTION", TokenType::KW_FUNCTION), + CHECK_SEMANTIC_TYPE("function", TokenType::KW_FUNCTION), CHECK_SEMANTIC_TYPE("_type", TokenType::TYPE_PROP), CHECK_SEMANTIC_TYPE("_id", TokenType::ID_PROP), @@ -566,6 +568,9 @@ TEST(Scanner, Basic) { CHECK_SEMANTIC_VALUE("\"\\\\\\\\\110 \"", TokenType::STRING, "\\\\H "), CHECK_SEMANTIC_VALUE("\"己所不欲,勿施于人\"", TokenType::STRING, "己所不欲,勿施于人"), + + CHECK_SEMANTIC_VALUE("http://nebula-graph.io", TokenType::HTTP_URL, "http://nebula-graph.io"), + CHECK_SEMANTIC_VALUE("wasm://d2FzbQo=", TokenType::WASM_BASE64, "wasm://d2FzbQo="), }; #undef CHECK_SEMANTIC_TYPE #undef CHECK_SEMANTIC_VALUE From 7482cb5465989d9f4d3b73c4f98cccef7ef57105 Mon Sep 17 00:00:00 2001 From: Zhenzhen Zhao <229194950@qq.com> Date: Mon, 13 Dec 2021 13:54:26 +0000 Subject: [PATCH 2/3] fix: pass parser test --- src/graph/service/PermissionCheck.cpp | 2 +- src/graph/validator/MaintainValidator.h | 19 +++++++++ src/parser/MaintainSentences.cpp | 1 + src/parser/Sentence.h | 2 +- src/parser/test/ParserTest.cpp | 52 ++++++++++++------------- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/graph/service/PermissionCheck.cpp b/src/graph/service/PermissionCheck.cpp index dc2a0288db7..49c734269a3 100644 --- a/src/graph/service/PermissionCheck.cpp +++ b/src/graph/service/PermissionCheck.cpp @@ -85,7 +85,7 @@ Status PermissionCheck::permissionCheck(ClientSession *session, case Sentence::Kind::kDropTag: case Sentence::Kind::kDropEdge: case Sentence::Kind::kCreateFunction: - case Sentence::Kind::kAlterFunction: + // case Sentence::Kind::kAlterFunction: case Sentence::Kind::kDropFunction: case Sentence::Kind::kCreateTagIndex: case Sentence::Kind::kCreateEdgeIndex: diff --git a/src/graph/validator/MaintainValidator.h b/src/graph/validator/MaintainValidator.h index 85317ad06f5..552a9ea4d85 100644 --- a/src/graph/validator/MaintainValidator.h +++ b/src/graph/validator/MaintainValidator.h @@ -14,6 +14,15 @@ namespace nebula { namespace graph { +class CreateFunctionValidator final : public Validator { + public: + CreateFunctionValidator(Sentence* sentence, QueryContext* context) + : Validator(sentence, context) {} + + private: + Status validateImpl() override; +}; + class CreateTagValidator final : public Validator { public: CreateTagValidator(Sentence* sentence, QueryContext* context) : Validator(sentence, context) {} @@ -124,6 +133,16 @@ class ShowEdgesValidator final : public Validator { Status toPlan() override; }; +class DropFunctionValidator final : public Validator { + public: + DropFunctionValidator(Sentence *sentence, QueryContext* context) : Validator(sentence, context) {} + + private: + Status validateImpl() override; + + Status toPlan() override; +}; + class DropTagValidator final : public Validator { public: DropTagValidator(Sentence* sentence, QueryContext* context) : Validator(sentence, context) {} diff --git a/src/parser/MaintainSentences.cpp b/src/parser/MaintainSentences.cpp index e474cbf2e43..47b43d20d57 100644 --- a/src/parser/MaintainSentences.cpp +++ b/src/parser/MaintainSentences.cpp @@ -101,6 +101,7 @@ std::string CreateFunctionSentence::toString() const { buf += "`"; buf += *name_; buf += "` "; + buf += "FROM "; buf += funcSource_->toString(); return buf; } diff --git a/src/parser/Sentence.h b/src/parser/Sentence.h index 949ebaca736..42aa0afa300 100644 --- a/src/parser/Sentence.h +++ b/src/parser/Sentence.h @@ -40,7 +40,7 @@ class Sentence { kCreateTag, kAlterTag, kCreateFunction, - kAlterFunction, + // kAlterFunction, kDropFunction, kCreateEdge, kAlterEdge, diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index 6c7c886c4d1..25338670dc0 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -399,34 +399,30 @@ TEST_F(ParserTest, TagOperation) { TEST_F(ParserTest, FunctionOperation) { { - std::string query = "CREATE FUNCTION `f1 FROM wasm://d2FzbQo="; - auto result = parse(query); - ASSERT_TRUE(result.ok()) << result.status(); - } - // { - // std::string query = - // "CREATE FUNCTION f1 FROM http://nebula-graph.io/remote/f1"; - // auto result = parse(query); - // ASSERT_TRUE(result.ok()) << result.status(); - // } - // { - // std::string query = - // "CREATE FUNCTION IF NOT EXISTS f1 FROM wasm://d2FzbQo="; - // auto result = parse(query); - // ASSERT_TRUE(result.ok()) << result.status(); - // } - // { - // std::string query = - // "CREATE FUNCTION IF NOT EXISTS f1 FROM http://nebula-graph.io/remote/f1"; - // auto result = parse(query); - // ASSERT_TRUE(result.ok()) << result.status(); - // } - // { - // std::string query = - // "DROP FUNCTION f1"; - // auto result = parse(query); - // ASSERT_TRUE(result.ok()) << result.status(); - // } + std::string query = "CREATE FUNCTION f1 FROM wasm://d2FzbQo="; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "CREATE FUNCTION f1 FROM http://nebula-graph.io/remote/f1"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "CREATE FUNCTION IF NOT EXISTS f1 FROM wasm://d2FzbQo="; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "CREATE FUNCTION IF NOT EXISTS f1 FROM http://nebula-graph.io/remote/f1"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "DROP FUNCTION f1"; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } } TEST_F(ParserTest, EdgeOperation) { From 9e28dfab0e0208ad6b39452787e101727f52fb48 Mon Sep 17 00:00:00 2001 From: Zhenzhen Zhao <229194950@qq.com> Date: Mon, 13 Dec 2021 15:38:34 +0000 Subject: [PATCH 3/3] chore: add example in validator --- src/graph/validator/MaintainValidator.cpp | 13 +++++++++++++ src/parser/MaintainSentences.h | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/src/graph/validator/MaintainValidator.cpp b/src/graph/validator/MaintainValidator.cpp index c55634c397d..c0ca0554c7d 100644 --- a/src/graph/validator/MaintainValidator.cpp +++ b/src/graph/validator/MaintainValidator.cpp @@ -141,6 +141,15 @@ static Status checkColName(const std::vector specs) { Status CreateFunctionValidator::validateImpl() { // TODO(TripleZ): add create function logic + auto sentence = static_cast(sentence_); + auto name = *sentence->name(); + auto functionSource = *sentence->getFunctionSource(); + auto funcType = functionSource.getType(); + auto funcSource = functionSource.getSource(); + + std::cout << " => create function: name(" + name + "), type(" + + funcType + "), source(" + funcSource + ")" << std::endl; + return Status::OK(); } @@ -278,6 +287,10 @@ Status DropFunctionValidator::validateImpl() { return Status::OK(); } Status DropFunctionValidator::toPlan() { // TODO(TripleZ): add drop function logic + auto sentence = static_cast(sentence_); + auto name = *sentence->name(); + std::cout << " => drop function: name(" + name + ")" << std::endl; + return Status::OK(); } diff --git a/src/parser/MaintainSentences.h b/src/parser/MaintainSentences.h index 2b51e8b2469..39e9c92e0fe 100644 --- a/src/parser/MaintainSentences.h +++ b/src/parser/MaintainSentences.h @@ -139,6 +139,14 @@ class FunctionSource final { return source_; } + std::string getType() const { + return type_; + } + + std::string getSource() const { + return source_; + } + private: std::string type_; std::string source_;