From 5aeaad198bba8954eb4cf724b9df8c01ca6e3e68 Mon Sep 17 00:00:00 2001 From: Antonio Andelic <antonio2368@users.noreply.github.com> Date: Thu, 10 Feb 2022 10:30:14 +0100 Subject: [PATCH] Define SHOW VERSION query (#265) --- src/query/exceptions.hpp | 7 +++++++ src/query/frontend/ast/ast.lcp | 8 ++++++++ src/query/frontend/ast/ast_visitor.hpp | 9 +++++---- .../frontend/ast/cypher_main_visitor.cpp | 6 ++++++ .../frontend/ast/cypher_main_visitor.hpp | 5 +++++ .../opencypher/grammar/MemgraphCypher.g4 | 6 ++++++ .../opencypher/grammar/MemgraphCypherLexer.g4 | 1 + .../frontend/semantic/required_privileges.cpp | 2 ++ .../frontend/stripped_lexer_constants.hpp | 3 ++- src/query/interpreter.cpp | 20 +++++++++++++++++++ tests/unit/cypher_main_visitor.cpp | 9 +++++++++ tests/unit/query_required_privileges.cpp | 7 ++++++- 12 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/query/exceptions.hpp b/src/query/exceptions.hpp index f0881de94..885e7eebb 100644 --- a/src/query/exceptions.hpp +++ b/src/query/exceptions.hpp @@ -217,4 +217,11 @@ class SettingConfigInMulticommandTxException final : public QueryException { SettingConfigInMulticommandTxException() : QueryException("Settings cannot be changed or fetched in multicommand transactions.") {} }; + +class VersionInfoInMulticommandTxException : public QueryException { + public: + VersionInfoInMulticommandTxException() + : QueryException("Version info query not allowed in multicommand transactions.") {} +}; + } // namespace query diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp index 167fca065..b08833c87 100644 --- a/src/query/frontend/ast/ast.lcp +++ b/src/query/frontend/ast/ast.lcp @@ -2615,4 +2615,12 @@ cpp<# (:serialize (:slk)) (:clone)) +(lcp:define-class version-query (query) () + (:public + #>cpp + DEFVISITABLE(QueryVisitor<void>); + cpp<#) + (:serialize (:slk)) + (:clone)) + (lcp:pop-namespace) ;; namespace query diff --git a/src/query/frontend/ast/ast_visitor.hpp b/src/query/frontend/ast/ast_visitor.hpp index 40c70ae8a..022af65ef 100644 --- a/src/query/frontend/ast/ast_visitor.hpp +++ b/src/query/frontend/ast/ast_visitor.hpp @@ -92,6 +92,7 @@ class IsolationLevelQuery; class CreateSnapshotQuery; class StreamQuery; class SettingQuery; +class VersionQuery; using TreeCompositeVisitor = ::utils::CompositeVisitor< SingleQuery, CypherUnion, NamedExpression, OrOperator, XorOperator, AndOperator, NotOperator, AdditionOperator, @@ -123,9 +124,9 @@ class ExpressionVisitor None, ParameterLookup, Identifier, PrimitiveLiteral, RegexMatch> {}; template <class TResult> -class QueryVisitor - : public ::utils::Visitor<TResult, CypherQuery, ExplainQuery, ProfileQuery, IndexQuery, AuthQuery, InfoQuery, - ConstraintQuery, DumpQuery, ReplicationQuery, LockPathQuery, FreeMemoryQuery, - TriggerQuery, IsolationLevelQuery, CreateSnapshotQuery, StreamQuery, SettingQuery> {}; +class QueryVisitor : public ::utils::Visitor<TResult, CypherQuery, ExplainQuery, ProfileQuery, IndexQuery, AuthQuery, + InfoQuery, ConstraintQuery, DumpQuery, ReplicationQuery, LockPathQuery, + FreeMemoryQuery, TriggerQuery, IsolationLevelQuery, CreateSnapshotQuery, + StreamQuery, SettingQuery, VersionQuery> {}; } // namespace query diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index b80bc7278..ab2e02cc6 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -870,6 +870,12 @@ antlrcpp::Any CypherMainVisitor::visitShowSettings(MemgraphCypher::ShowSettingsC return setting_query; } +antlrcpp::Any CypherMainVisitor::visitVersionQuery(MemgraphCypher::VersionQueryContext * /*ctx*/) { + auto *version_query = storage_->Create<VersionQuery>(); + query_ = version_query; + return version_query; +} + antlrcpp::Any CypherMainVisitor::visitCypherUnion(MemgraphCypher::CypherUnionContext *ctx) { bool distinct = !ctx->ALL(); auto *cypher_union = storage_->Create<CypherUnion>(distinct); diff --git a/src/query/frontend/ast/cypher_main_visitor.hpp b/src/query/frontend/ast/cypher_main_visitor.hpp index 431b58480..5b36dc45b 100644 --- a/src/query/frontend/ast/cypher_main_visitor.hpp +++ b/src/query/frontend/ast/cypher_main_visitor.hpp @@ -359,6 +359,11 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor { */ antlrcpp::Any visitShowSettings(MemgraphCypher::ShowSettingsContext *ctx) override; + /** + * @return VersionQuery* + */ + antlrcpp::Any visitVersionQuery(MemgraphCypher::VersionQueryContext *ctx) override; + /** * @return CypherUnion* */ diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 index d91bb42e8..be9497e20 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypher.g4 @@ -54,6 +54,7 @@ memgraphCypherKeyword : cypherKeyword | HEADER | IDENTIFIED | ISOLATION + | KAFKA | LEVEL | LOAD | LOCK @@ -62,6 +63,7 @@ memgraphCypherKeyword : cypherKeyword | NEXT | NO | PASSWORD + | PULSAR | PORT | PRIVILEGES | READ @@ -94,6 +96,7 @@ memgraphCypherKeyword : cypherKeyword | UPDATE | USER | USERS + | VERSION ; symbolicName : UnescapedSymbolicName @@ -117,6 +120,7 @@ query : cypherQuery | createSnapshotQuery | streamQuery | settingQuery + | versionQuery ; authQuery : createRole @@ -353,3 +357,5 @@ setSetting : SET DATABASE SETTING settingName TO settingValue ; showSetting : SHOW DATABASE SETTING settingName ; showSettings : SHOW DATABASE SETTINGS ; + +versionQuery : SHOW VERSION ; diff --git a/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 b/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 index 50556df8f..e678a73e9 100644 --- a/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 +++ b/src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 @@ -109,3 +109,4 @@ UNLOCK : U N L O C K ; UPDATE : U P D A T E ; USER : U S E R ; USERS : U S E R S ; +VERSION : V E R S I O N ; diff --git a/src/query/frontend/semantic/required_privileges.cpp b/src/query/frontend/semantic/required_privileges.cpp index 349f09fc6..6e61dfc2c 100644 --- a/src/query/frontend/semantic/required_privileges.cpp +++ b/src/query/frontend/semantic/required_privileges.cpp @@ -76,6 +76,8 @@ class PrivilegeExtractor : public QueryVisitor<void>, public HierarchicalTreeVis void Visit(SettingQuery & /*setting_query*/) override { AddPrivilege(AuthQuery::Privilege::CONFIG); } + void Visit(VersionQuery & /*version_query*/) override { AddPrivilege(AuthQuery::Privilege::STATS); } + bool PreVisit(Create & /*unused*/) override { AddPrivilege(AuthQuery::Privilege::CREATE); return false; diff --git a/src/query/frontend/stripped_lexer_constants.hpp b/src/query/frontend/stripped_lexer_constants.hpp index ff28498b1..39b765971 100644 --- a/src/query/frontend/stripped_lexer_constants.hpp +++ b/src/query/frontend/stripped_lexer_constants.hpp @@ -202,7 +202,8 @@ const trie::Trie kKeywords = {"union", "bootstrap_servers", "kafka", "pulsar", - "service_url"}; + "service_url", + "version"}; // Unicode codepoints that are allowed at the start of the unescaped name. const std::bitset<kBitsetSize> kUnescapedNameAllowedStarts( diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index 18c3089a9..e119e352b 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -1725,6 +1725,24 @@ PreparedQuery PrepareSettingQuery(ParsedQuery parsed_query, const bool in_explic // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) } +PreparedQuery PrepareVersionQuery(ParsedQuery parsed_query, const bool in_explicit_transaction) { + if (in_explicit_transaction) { + throw VersionInfoInMulticommandTxException(); + } + + return PreparedQuery{{"version"}, + std::move(parsed_query.required_privileges), + [](AnyStream *stream, std::optional<int> /*n*/) { + std::vector<TypedValue> version_value; + version_value.reserve(1); + + version_value.emplace_back(gflags::VersionString()); + stream->Result(version_value); + return QueryHandlerResult::COMMIT; + }, + RWType::NONE}; +} + PreparedQuery PrepareInfoQuery(ParsedQuery parsed_query, bool in_explicit_transaction, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, storage::Storage *db, utils::MemoryResource *execution_memory) { @@ -2128,6 +2146,8 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, PrepareCreateSnapshotQuery(std::move(parsed_query), in_explicit_transaction_, interpreter_context_); } else if (utils::Downcast<SettingQuery>(parsed_query.query)) { prepared_query = PrepareSettingQuery(std::move(parsed_query), in_explicit_transaction_, &*execution_db_accessor_); + } else if (utils::Downcast<VersionQuery>(parsed_query.query)) { + prepared_query = PrepareVersionQuery(std::move(parsed_query), in_explicit_transaction_); } else { LOG_FATAL("Should not get here -- unknown query type!"); } diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index c3fd82a23..6d1d469c8 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -4060,3 +4060,12 @@ TEST_P(CypherMainVisitorTest, SettingQuery) { validate_setting_query("SET DATABASE SETTING 'setting' TO 'value'", SettingQuery::Action::SET_SETTING, TypedValue{"setting"}, TypedValue{"value"}); } + +TEST_P(CypherMainVisitorTest, VersionQuery) { + auto &ast_generator = *GetParam(); + + TestInvalidQuery("SHOW VERION", ast_generator); + TestInvalidQuery("SHOW VER", ast_generator); + TestInvalidQuery("SHOW VERSIONS", ast_generator); + ASSERT_NO_THROW(ast_generator.ParseQuery("SHOW VERSION")); +} diff --git a/tests/unit/query_required_privileges.cpp b/tests/unit/query_required_privileges.cpp index 314b52ec3..aea519ce4 100644 --- a/tests/unit/query_required_privileges.cpp +++ b/tests/unit/query_required_privileges.cpp @@ -1,4 +1,4 @@ -// Copyright 2021 Memgraph Ltd. +// Copyright 2022 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -186,3 +186,8 @@ TEST_F(TestPrivilegeExtractor, SettingQuery) { auto *query = storage.Create<SettingQuery>(); EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::CONFIG)); } + +TEST_F(TestPrivilegeExtractor, ShowVersion) { + auto *query = storage.Create<VersionQuery>(); + EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::STATS)); +}