mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-19 16:20:50 +00:00
Merge bdf6bdf693
into f4038e3153
This commit is contained in:
commit
bde1e77af7
@ -730,7 +730,8 @@ bool Client::processWithFuzzing(const String & full_query)
|
||||
}
|
||||
|
||||
// Kusto is not a subject for fuzzing (yet)
|
||||
if (client_context->getSettingsRef().dialect == DB::Dialect::kusto)
|
||||
if (client_context->getSettingsRef().dialect == DB::Dialect::kusto
|
||||
|| client_context->getSettingsRef().dialect == DB::Dialect::mongo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -46,6 +46,8 @@
|
||||
#include <Parsers/PRQL/ParserPRQLQuery.h>
|
||||
#include <Parsers/Kusto/ParserKQLStatement.h>
|
||||
#include <Parsers/Kusto/parseKQLQuery.h>
|
||||
#include <Parsers/Mongo/parseMongoQuery.h>
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
#include <Processors/Formats/Impl/NullFormat.h>
|
||||
#include <Processors/Formats/IInputFormat.h>
|
||||
@ -302,6 +304,8 @@ ASTPtr ClientBase::parseQuery(const char *& pos, const char * end, const Setting
|
||||
parser = std::make_unique<ParserKQLStatement>(end, settings.allow_settings_after_format_in_insert);
|
||||
else if (dialect == Dialect::prql)
|
||||
parser = std::make_unique<ParserPRQLQuery>(max_length, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else if (dialect == Dialect::mongo)
|
||||
parser = std::make_unique<Mongo::ParserMongoQuery>(max_length, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else
|
||||
parser = std::make_unique<ParserQuery>(end, settings.allow_settings_after_format_in_insert);
|
||||
|
||||
@ -310,6 +314,8 @@ ASTPtr ClientBase::parseQuery(const char *& pos, const char * end, const Setting
|
||||
String message;
|
||||
if (dialect == Dialect::kusto)
|
||||
res = tryParseKQLQuery(*parser, pos, end, message, true, "", allow_multi_statements, max_length, settings.max_parser_depth, settings.max_parser_backtracks, true);
|
||||
else if (dialect == Dialect::mongo)
|
||||
res = Mongo::tryParseMongoQuery(*parser, pos, end, message, true, "", allow_multi_statements, max_length, settings.max_parser_depth, settings.max_parser_backtracks, true);
|
||||
else
|
||||
res = tryParseQuery(*parser, pos, end, message, true, "", allow_multi_statements, max_length, settings.max_parser_depth, settings.max_parser_backtracks, true);
|
||||
|
||||
@ -323,6 +329,8 @@ ASTPtr ClientBase::parseQuery(const char *& pos, const char * end, const Setting
|
||||
{
|
||||
if (dialect == Dialect::kusto)
|
||||
res = parseKQLQueryAndMovePosition(*parser, pos, end, "", allow_multi_statements, max_length, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else if (dialect == Dialect::mongo)
|
||||
res = Mongo::parseMongoQueryAndMovePosition(*parser, pos, end, "", allow_multi_statements, max_length, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else
|
||||
res = parseQueryAndMovePosition(*parser, pos, end, "", allow_multi_statements, max_length, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <Parsers/PRQL/ParserPRQLQuery.h>
|
||||
#include <Parsers/Kusto/ParserKQLStatement.h>
|
||||
#include <Parsers/Kusto/parseKQLQuery.h>
|
||||
#include <Parsers/Mongo/parseMongoQuery.h>
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -165,12 +167,16 @@ void LocalConnection::sendQuery(
|
||||
parser = std::make_unique<ParserKQLStatement>(end, settings.allow_settings_after_format_in_insert);
|
||||
else if (dialect == Dialect::prql)
|
||||
parser = std::make_unique<ParserPRQLQuery>(settings.max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else if (dialect == Dialect::mongo)
|
||||
parser = std::make_unique<Mongo::ParserMongoQuery>(settings.max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else
|
||||
parser = std::make_unique<ParserQuery>(end, settings.allow_settings_after_format_in_insert);
|
||||
|
||||
ASTPtr parsed_query;
|
||||
if (dialect == Dialect::kusto)
|
||||
parsed_query = parseKQLQueryAndMovePosition(*parser, begin, end, "", /*allow_multi_statements*/false, settings.max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else if (dialect == Dialect::mongo)
|
||||
parsed_query = Mongo::parseMongoQueryAndMovePosition(*parser, begin, end, "", /*allow_multi_statements*/false, settings.max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
else
|
||||
parsed_query = parseQueryAndMovePosition(*parser, begin, end, "", /*allow_multi_statements*/false, settings.max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
|
||||
|
@ -166,7 +166,8 @@ IMPLEMENT_SETTING_ENUM(MsgPackUUIDRepresentation, ErrorCodes::BAD_ARGUMENTS,
|
||||
IMPLEMENT_SETTING_ENUM(Dialect, ErrorCodes::BAD_ARGUMENTS,
|
||||
{{"clickhouse", Dialect::clickhouse},
|
||||
{"kusto", Dialect::kusto},
|
||||
{"prql", Dialect::prql}})
|
||||
{"prql", Dialect::prql},
|
||||
{"mongo", Dialect::mongo}})
|
||||
|
||||
|
||||
IMPLEMENT_SETTING_ENUM(ParallelReplicasCustomKeyFilterType, ErrorCodes::BAD_ARGUMENTS,
|
||||
|
@ -295,6 +295,7 @@ enum class Dialect : uint8_t
|
||||
clickhouse,
|
||||
kusto,
|
||||
prql,
|
||||
mongo,
|
||||
};
|
||||
|
||||
DECLARE_SETTING_ENUM(Dialect)
|
||||
|
@ -66,6 +66,9 @@
|
||||
#include <Interpreters/executeQuery.h>
|
||||
#include <Interpreters/DatabaseCatalog.h>
|
||||
#include <Common/ProfileEvents.h>
|
||||
#include "Core/SettingsEnums.h"
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
#include <Parsers/Mongo/parseMongoQuery.h>
|
||||
|
||||
#include <IO/CompressionMethod.h>
|
||||
|
||||
@ -715,7 +718,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
ReadBuffer * istr)
|
||||
{
|
||||
const bool internal = flags.internal;
|
||||
|
||||
std::string full_inp(begin, end);
|
||||
/// query_span is a special span, when this function exits, it's lifetime is not ended, but ends when the query finishes.
|
||||
/// Some internal queries might call this function recursively by setting 'internal' parameter to 'true',
|
||||
/// to make sure SpanHolders in current stack ends in correct order, we disable this span for these internal queries
|
||||
@ -776,6 +779,11 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
ParserPRQLQuery parser(max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
}
|
||||
else if (settings.dialect == Dialect::mongo && !internal)
|
||||
{
|
||||
Mongo::ParserMongoQuery parser(max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
ast = parseMongoQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth, settings.max_parser_backtracks);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParserQuery parser(end, settings.allow_settings_after_format_in_insert);
|
||||
@ -822,8 +830,9 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
|
||||
const char * query_end = end;
|
||||
if (const auto * insert_query = ast->as<ASTInsertQuery>(); insert_query && insert_query->data)
|
||||
{
|
||||
query_end = insert_query->data;
|
||||
|
||||
}
|
||||
bool is_create_parameterized_view = false;
|
||||
if (const auto * create_query = ast->as<ASTCreateQuery>())
|
||||
{
|
||||
@ -839,7 +848,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
|
||||
/// Replace ASTQueryParameter with ASTLiteral for prepared statements.
|
||||
/// Even if we don't have parameters in query_context, check that AST doesn't have unknown parameters
|
||||
bool probably_has_params = find_first_symbols<'{'>(begin, end) != end;
|
||||
if (!is_create_parameterized_view && probably_has_params)
|
||||
if (!is_create_parameterized_view && probably_has_params && settings.dialect != Dialect::mongo)
|
||||
{
|
||||
ReplaceQueryParameterVisitor visitor(context->getQueryParameters());
|
||||
visitor.visit(ast);
|
||||
|
@ -5,9 +5,14 @@ add_headers_and_sources(clickhouse_parsers ./Access)
|
||||
add_headers_and_sources(clickhouse_parsers ./MySQL)
|
||||
add_headers_and_sources(clickhouse_parsers ./Kusto)
|
||||
add_headers_and_sources(clickhouse_parsers ./PRQL)
|
||||
add_headers_and_sources(clickhouse_parsers ./Mongo)
|
||||
add_headers_and_sources(clickhouse_parsers ./Kusto/KustoFunctions)
|
||||
add_library(clickhouse_parsers ${clickhouse_parsers_headers} ${clickhouse_parsers_sources})
|
||||
target_link_libraries(clickhouse_parsers PUBLIC clickhouse_common_io clickhouse_common_access)
|
||||
if (TARGET ch_contrib::rapidjson)
|
||||
target_link_libraries(clickhouse_parsers PRIVATE ch_contrib::rapidjson)
|
||||
endif ()
|
||||
|
||||
if (TARGET ch_rust::prql)
|
||||
target_link_libraries(clickhouse_parsers PRIVATE ch_rust::prql)
|
||||
endif ()
|
||||
|
59
src/Parsers/Mongo/Metadata.cpp
Normal file
59
src/Parsers/Mongo/Metadata.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "Metadata.h"
|
||||
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
QueryMetadata::QueryMetadata(
|
||||
const char * begin, const char * end, QueryType query_type_, std::optional<int> limit_, std::optional<std::string> order_by_)
|
||||
: collection_name(begin, end), query_type(query_type_), limit(limit_), order_by(order_by_)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<QueryMetadata> extractMetadataFromRequest(const char * begin, const char * end)
|
||||
{
|
||||
auto [token_begin, token_end] = getMetadataSubstring(begin, end);
|
||||
|
||||
const char * token_begin_collection_name = findKth<'.'>(token_begin, token_end, 1) + 1;
|
||||
const char * token_end_collection_name = findKth<'.'>(token_begin, token_end, 2);
|
||||
|
||||
const char * token_begin_query_type = token_end_collection_name + 1;
|
||||
const char * token_end_query_type = token_end;
|
||||
|
||||
std::string key(token_begin_query_type, token_end_query_type);
|
||||
std::optional<QueryMetadata::QueryType> query_type;
|
||||
|
||||
for (const auto & [key_query, query] : QueryMetadata::queryTypeKeyWords)
|
||||
{
|
||||
if (key_query == key)
|
||||
{
|
||||
query_type = query;
|
||||
}
|
||||
}
|
||||
|
||||
if (!query_type)
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid query");
|
||||
}
|
||||
|
||||
MongoQueryKeyNameExtractor limit_extractor(".limit");
|
||||
auto limit = limit_extractor.extractInt(begin, end);
|
||||
|
||||
MongoQueryKeyNameExtractor order_by_extractor(".sort");
|
||||
auto order_by = order_by_extractor.extractString(begin, end);
|
||||
|
||||
return std::make_shared<QueryMetadata>(token_begin_collection_name, token_end_collection_name, *query_type, limit, order_by);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
57
src/Parsers/Mongo/Metadata.h
Normal file
57
src/Parsers/Mongo/Metadata.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
/// Metadata for MongoDB queries. Contains collection, query type, limi and order by data.
|
||||
class QueryMetadata
|
||||
{
|
||||
public:
|
||||
bool add_data_to_query = true;
|
||||
|
||||
enum class QueryType : uint8_t
|
||||
{
|
||||
select = 0,
|
||||
insert_many = 1,
|
||||
insert_one = 2,
|
||||
};
|
||||
|
||||
static constexpr std::pair<const char *, QueryType> queryTypeKeyWords[] = {
|
||||
{"find", QueryType::select},
|
||||
{"insertMany", QueryType::insert_many},
|
||||
{"insertOne", QueryType::insert_one},
|
||||
};
|
||||
|
||||
static constexpr size_t queryTypeKeyWordsLength = sizeof(queryTypeKeyWords) / sizeof(queryTypeKeyWords[0]);
|
||||
|
||||
explicit QueryMetadata(
|
||||
const char * begin, const char * end, QueryType query_type_, std::optional<int> limit_, std::optional<std::string> order_by_);
|
||||
|
||||
const std::string & getCollectionName() const { return collection_name; }
|
||||
|
||||
QueryType getQueryType() const { return query_type; }
|
||||
|
||||
std::optional<size_t> getLimit() const { return limit; }
|
||||
|
||||
std::optional<std::string> getOrderBy() const { return order_by; }
|
||||
|
||||
private:
|
||||
std::string collection_name;
|
||||
QueryType query_type;
|
||||
std::optional<size_t> limit;
|
||||
std::optional<std::string> order_by;
|
||||
};
|
||||
|
||||
std::shared_ptr<QueryMetadata> extractMetadataFromRequest(const char * begin, const char * end);
|
||||
|
||||
}
|
||||
|
||||
}
|
35
src/Parsers/Mongo/ParserMongoCompareFunctions.cpp
Normal file
35
src/Parsers/Mongo/ParserMongoCompareFunctions.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "ParserMongoCompareFunctions.h"
|
||||
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool ICompareFunction::parseImpl(ASTPtr & node)
|
||||
{
|
||||
auto identifier = std::make_shared<ASTIdentifier>(edge_name);
|
||||
if (data.IsInt())
|
||||
{
|
||||
auto literal = std::make_shared<ASTLiteral>(Field(data.GetInt()));
|
||||
auto where_condition = makeASTFunction(getFunctionAlias(), identifier, literal);
|
||||
node = where_condition;
|
||||
return true;
|
||||
}
|
||||
if (data.IsString())
|
||||
{
|
||||
auto literal = std::make_shared<ASTLiteral>(Field(data.GetString()));
|
||||
auto where_condition = makeASTFunction(getFunctionAlias(), identifier, literal);
|
||||
node = where_condition;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
107
src/Parsers/Mongo/ParserMongoCompareFunctions.h
Normal file
107
src/Parsers/Mongo/ParserMongoCompareFunctions.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoFunction.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class ICompareFunction : public IMongoFunction
|
||||
{
|
||||
public:
|
||||
explicit ICompareFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string getFunctionAlias() const = 0;
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
};
|
||||
|
||||
class MongoLtFunction : public ICompareFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$lt"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "less"; }
|
||||
|
||||
explicit MongoLtFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: ICompareFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MongoLteFunction : public ICompareFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$lte"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "lessOrEquals"; }
|
||||
|
||||
|
||||
explicit MongoLteFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: ICompareFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoGtFunction : public ICompareFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$gt"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "greater"; }
|
||||
|
||||
explicit MongoGtFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: ICompareFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoGteFunction : public ICompareFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$gte"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "greaterOrEquals"; }
|
||||
|
||||
explicit MongoGteFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: ICompareFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoNotEqualsFunction : public ICompareFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$ne"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "notEquals"; }
|
||||
|
||||
explicit MongoNotEqualsFunction(
|
||||
rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: ICompareFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoLikeFunction : public ICompareFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$regex"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "like"; }
|
||||
|
||||
explicit MongoLikeFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: ICompareFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
54
src/Parsers/Mongo/ParserMongoFilter.cpp
Normal file
54
src/Parsers/Mongo/ParserMongoFilter.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "ParserMongoFilter.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Parsers/ASTQueryParameter.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool ParserMongoFilter::parseImpl(ASTPtr & node)
|
||||
{
|
||||
chassert(data.IsObject());
|
||||
std::vector<ASTPtr> child_trees;
|
||||
for (auto it = data.MemberBegin(); it != data.MemberEnd(); ++it)
|
||||
{
|
||||
auto parser = createParser(copyValue(it->value), metadata, it->name.GetString());
|
||||
ASTPtr child_node;
|
||||
if (!parser->parseImpl(child_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
child_trees.push_back(child_node);
|
||||
}
|
||||
|
||||
if (child_trees.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (child_trees.size() == 1)
|
||||
{
|
||||
node = child_trees[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
auto result = makeASTFunction("and");
|
||||
for (const auto & elem : child_trees)
|
||||
{
|
||||
result->arguments->children.push_back(elem);
|
||||
}
|
||||
node = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
31
src/Parsers/Mongo/ParserMongoFilter.h
Normal file
31
src/Parsers/Mongo/ParserMongoFilter.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
#include <Parsers/Mongo/Metadata.h>
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class ParserMongoFilter : public IMongoParser
|
||||
{
|
||||
public:
|
||||
explicit ParserMongoFilter(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoParser(std::move(data_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
|
||||
~ParserMongoFilter() override = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
186
src/Parsers/Mongo/ParserMongoFunction.cpp
Normal file
186
src/Parsers/Mongo/ParserMongoFunction.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
#include "ParserMongoFunction.h"
|
||||
|
||||
#include <Core/Field.h>
|
||||
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool MongoIdentityFunction::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (data.IsInt())
|
||||
{
|
||||
auto identifier = std::make_shared<ASTIdentifier>(edge_name);
|
||||
auto literal = std::make_shared<ASTLiteral>(Field(data.GetInt()));
|
||||
auto where_condition = makeASTFunction("equals", identifier, literal);
|
||||
node = where_condition;
|
||||
return true;
|
||||
}
|
||||
if (data.IsString())
|
||||
{
|
||||
auto identifier = std::make_shared<ASTIdentifier>(edge_name);
|
||||
auto literal = std::make_shared<ASTLiteral>(Field(data.GetString()));
|
||||
auto where_condition = makeASTFunction("equals", identifier, literal);
|
||||
node = where_condition;
|
||||
return true;
|
||||
}
|
||||
if (data.IsObject())
|
||||
{
|
||||
auto parser = createInversedParser(std::move(data), metadata, edge_name);
|
||||
if (!parser->parseImpl(node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MongoLiteralFunction::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (data.IsString())
|
||||
{
|
||||
auto literal = std::make_shared<ASTIdentifier>(data.GetString());
|
||||
node = literal;
|
||||
return true;
|
||||
}
|
||||
if (data.IsObject())
|
||||
{
|
||||
if (data.Size() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = data.MemberBegin();
|
||||
|
||||
const char * name = it->name.GetString();
|
||||
auto parser = createParser(copyValue(it->value), metadata, name);
|
||||
ASTPtr child_node;
|
||||
if (!parser->parseImpl(child_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
node = child_node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MongoOrFunction::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (!data.IsArray())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<ASTPtr> child_trees;
|
||||
for (unsigned int i = 0; i < data.Size(); ++i)
|
||||
{
|
||||
auto parser = createParser(copyValue(data[i]), metadata, "");
|
||||
ASTPtr child_node;
|
||||
if (!parser->parseImpl(child_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
child_trees.push_back(child_node);
|
||||
}
|
||||
|
||||
if (child_trees.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (child_trees.size() == 1)
|
||||
{
|
||||
node = child_trees[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
auto result = makeASTFunction("or");
|
||||
for (const auto & elem : child_trees)
|
||||
{
|
||||
result->arguments->children.push_back(elem);
|
||||
}
|
||||
node = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IMongoArithmeticFunction::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (data.Size() < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<ASTPtr> children;
|
||||
for (unsigned int i = 0; i < data.Size(); ++i)
|
||||
{
|
||||
auto parser = createParser(copyValue(data[i]), metadata, "$arithmetic_function_element");
|
||||
ASTPtr child_node;
|
||||
if (!parser->parseImpl(child_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
children.push_back(std::move(child_node));
|
||||
}
|
||||
|
||||
/// Wrap function as tree of binary operators like
|
||||
///
|
||||
/// +
|
||||
/// / \
|
||||
/// c0 +
|
||||
/// / \
|
||||
/// c1 c2
|
||||
///
|
||||
auto function = makeASTFunction(getFunctionAlias(), children[0], children[1]);
|
||||
for (size_t i = 2; i < children.size(); ++i)
|
||||
{
|
||||
function = makeASTFunction(getFunctionAlias(), function, children[i]);
|
||||
}
|
||||
node = function;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MongoArithmeticFunctionElement::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (data.IsInt())
|
||||
{
|
||||
auto literal = std::make_shared<ASTLiteral>(Field(data.GetInt()));
|
||||
node = literal;
|
||||
return true;
|
||||
}
|
||||
if (data.IsString())
|
||||
{
|
||||
auto identifier = std::make_shared<ASTIdentifier>(data.GetString());
|
||||
node = identifier;
|
||||
return true;
|
||||
}
|
||||
if (data.IsObject())
|
||||
{
|
||||
auto parser = createParser(std::move(data), metadata, "");
|
||||
if (!parser->parseImpl(node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
155
src/Parsers/Mongo/ParserMongoFunction.h
Normal file
155
src/Parsers/Mongo/ParserMongoFunction.h
Normal file
@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoSelectQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class IMongoFunction : public IMongoParser
|
||||
{
|
||||
protected:
|
||||
explicit IMongoFunction(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoParser(std::move(data_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual std::string getFunctionName() const = 0;
|
||||
|
||||
~IMongoFunction() override = default;
|
||||
};
|
||||
|
||||
class MongoIdentityFunction : public IMongoFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return edge_name; }
|
||||
|
||||
explicit MongoIdentityFunction(
|
||||
rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
};
|
||||
|
||||
class MongoLiteralFunction : public IMongoFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return edge_name; }
|
||||
|
||||
explicit MongoLiteralFunction(
|
||||
rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
};
|
||||
|
||||
|
||||
class MongoOrFunction : public IMongoFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$or"; }
|
||||
|
||||
explicit MongoOrFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
};
|
||||
|
||||
/// Base class for arithmetic functions like add, multiplication and others.
|
||||
class IMongoArithmeticFunction : public IMongoFunction
|
||||
{
|
||||
public:
|
||||
explicit IMongoArithmeticFunction(
|
||||
rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string getFunctionAlias() const = 0;
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
};
|
||||
|
||||
class MongoSumFunction : public IMongoArithmeticFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$add"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "plus"; }
|
||||
|
||||
explicit MongoSumFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoArithmeticFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoMultiplyFunction : public IMongoArithmeticFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$mul"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "multiply"; }
|
||||
|
||||
explicit MongoMultiplyFunction(
|
||||
rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoArithmeticFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoDivideFunction : public IMongoArithmeticFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$div"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "divide"; }
|
||||
|
||||
explicit MongoDivideFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoArithmeticFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MongoMinusFunction : public IMongoArithmeticFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$sub"; }
|
||||
|
||||
std::string getFunctionAlias() const override { return "minus"; }
|
||||
|
||||
explicit MongoMinusFunction(rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoArithmeticFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MongoArithmeticFunctionElement : public IMongoFunction
|
||||
{
|
||||
public:
|
||||
std::string getFunctionName() const override { return "$arithmetic_function_element"; }
|
||||
|
||||
explicit MongoArithmeticFunctionElement(
|
||||
rapidjson::Value array_elements_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoFunction(std::move(array_elements_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
31
src/Parsers/Mongo/ParserMongoInsertQuery.cpp
Normal file
31
src/Parsers/Mongo/ParserMongoInsertQuery.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "ParserMongoInsertQuery.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Parsers/ParserQuery.h>
|
||||
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
/// TODO (scanhex12): add insert queries in mongo
|
||||
bool ParserMongoInsertManyQuery::parseImpl(ASTPtr & node)
|
||||
{
|
||||
node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// TODO (scanhex12): add insert queries in mongo
|
||||
bool ParserMongoInsertOneQuery::parseImpl(ASTPtr & node)
|
||||
{
|
||||
node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
39
src/Parsers/Mongo/ParserMongoInsertQuery.h
Normal file
39
src/Parsers/Mongo/ParserMongoInsertQuery.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class ParserMongoInsertManyQuery : public IMongoParser
|
||||
{
|
||||
public:
|
||||
explicit ParserMongoInsertManyQuery(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_)
|
||||
: IMongoParser(std::move(data_), metadata_, "")
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
|
||||
~ParserMongoInsertManyQuery() override = default;
|
||||
};
|
||||
|
||||
class ParserMongoInsertOneQuery : public IMongoParser
|
||||
{
|
||||
public:
|
||||
explicit ParserMongoInsertOneQuery(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_)
|
||||
: IMongoParser(std::move(data_), metadata_, "")
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
|
||||
~ParserMongoInsertOneQuery() override = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
41
src/Parsers/Mongo/ParserMongoOrderBy.cpp
Normal file
41
src/Parsers/Mongo/ParserMongoOrderBy.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "Parsers/Mongo/ParserMongoOrderBy.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Parsers/ASTQueryParameter.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTOrderByElement.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool ParserMongoOrderBy::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (!data.IsObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = std::make_shared<ASTExpressionList>();
|
||||
for (auto it = data.MemberBegin(); it != data.MemberEnd(); ++it)
|
||||
{
|
||||
std::shared_ptr<ASTOrderByElement> element = std::make_shared<ASTOrderByElement>();
|
||||
element->direction = it->value.GetInt();
|
||||
element->children.push_back(std::make_shared<ASTIdentifier>(it->name.GetString()));
|
||||
result->children.push_back(element);
|
||||
}
|
||||
|
||||
node = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
31
src/Parsers/Mongo/ParserMongoOrderBy.h
Normal file
31
src/Parsers/Mongo/ParserMongoOrderBy.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
#include <Parsers/Mongo/Metadata.h>
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class ParserMongoOrderBy : public IMongoParser
|
||||
{
|
||||
public:
|
||||
explicit ParserMongoOrderBy(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoParser(std::move(data_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
|
||||
~ParserMongoOrderBy() override = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
54
src/Parsers/Mongo/ParserMongoProjection.cpp
Normal file
54
src/Parsers/Mongo/ParserMongoProjection.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "Parsers/Mongo/ParserMongoProjection.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Parsers/ASTQueryParameter.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool ParserMongoProjection::parseImpl(ASTPtr & node)
|
||||
{
|
||||
if (!data.IsObject())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = std::make_shared<ASTExpressionList>();
|
||||
for (auto it = data.MemberBegin(); it != data.MemberEnd(); ++it)
|
||||
{
|
||||
if (it->value.IsInt())
|
||||
{
|
||||
auto include_field = it->value.GetInt();
|
||||
if (include_field)
|
||||
{
|
||||
result->children.push_back(std::make_shared<ASTIdentifier>(it->name.GetString()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ASTPtr child_node;
|
||||
auto parser = createParser(copyValue(it->value), metadata, it->name.GetString(), true);
|
||||
if (!parser->parseImpl(child_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
child_node->setAlias(it->name.GetString());
|
||||
result->children.push_back(child_node);
|
||||
}
|
||||
|
||||
node = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
31
src/Parsers/Mongo/ParserMongoProjection.h
Normal file
31
src/Parsers/Mongo/ParserMongoProjection.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
#include <Parsers/Mongo/Metadata.h>
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class ParserMongoProjection : public IMongoParser
|
||||
{
|
||||
public:
|
||||
explicit ParserMongoProjection(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: IMongoParser(std::move(data_), metadata_, edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
|
||||
~ParserMongoProjection() override = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
127
src/Parsers/Mongo/ParserMongoQuery.cpp
Normal file
127
src/Parsers/Mongo/ParserMongoQuery.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#include "ParserMongoQuery.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Core/Settings.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Common/CurrentThread.h>
|
||||
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTSelectQuery.h>
|
||||
#include <Parsers/ASTTablesInSelectQuery.h>
|
||||
#include <Parsers/IParserBase.h>
|
||||
#include <Parsers/ASTAsterisk.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||
#include <Parsers/ASTSubquery.h>
|
||||
#include <Parsers/ASTWithElement.h>
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoFilter.h>
|
||||
#include <Parsers/Mongo/ParserMongoFunction.h>
|
||||
#include <Parsers/Mongo/ParserMongoSelectQuery.h>
|
||||
#include <Parsers/Mongo/Metadata.h>
|
||||
#include <Parsers/Mongo/ParserMongoInsertQuery.h>
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
#include <Parsers/Mongo/ParserMongoCompareFunctions.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool ParserMongoQuery::parseImpl(Pos & /*pos*/, ASTPtr & node, Expected & /*expected*/)
|
||||
{
|
||||
switch (metadata->getQueryType())
|
||||
{
|
||||
case QueryMetadata::QueryType::select:
|
||||
{
|
||||
return ParserMongoSelectQuery(std::move(data), metadata).parseImpl(node);
|
||||
}
|
||||
case QueryMetadata::QueryType::insert_many:
|
||||
{
|
||||
return ParserMongoInsertManyQuery(std::move(data), metadata).parseImpl(node);
|
||||
}
|
||||
case QueryMetadata::QueryType::insert_one:
|
||||
{
|
||||
return ParserMongoInsertOneQuery(std::move(data), metadata).parseImpl(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<IMongoParser>
|
||||
createParser(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_, bool literal_as_default)
|
||||
{
|
||||
if (edge_name_ == "$or")
|
||||
{
|
||||
return std::make_shared<MongoOrFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (edge_name_ == "$add")
|
||||
{
|
||||
return std::make_shared<MongoSumFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (edge_name_ == "$mul")
|
||||
{
|
||||
return std::make_shared<MongoMultiplyFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (edge_name_ == "$div")
|
||||
{
|
||||
return std::make_shared<MongoDivideFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (edge_name_ == "$sub")
|
||||
{
|
||||
return std::make_shared<MongoMinusFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (edge_name_ == "")
|
||||
{
|
||||
return std::make_shared<ParserMongoFilter>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (edge_name_ == "$arithmetic_function_element")
|
||||
{
|
||||
return std::make_shared<MongoArithmeticFunctionElement>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
if (!literal_as_default)
|
||||
{
|
||||
return std::make_shared<MongoIdentityFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_shared<MongoLiteralFunction>(std::move(data_), metadata_, edge_name_);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<IMongoParser>
|
||||
createInversedParser(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
{
|
||||
if (static_cast<std::string>(data_.MemberBegin()->name.GetString()) == "$lt")
|
||||
{
|
||||
return std::make_shared<MongoLtFunction>(copyValue(data_.MemberBegin()->value), metadata_, edge_name_);
|
||||
}
|
||||
if (static_cast<std::string>(data_.MemberBegin()->name.GetString()) == "$lte")
|
||||
{
|
||||
return std::make_shared<MongoLteFunction>(copyValue(data_.MemberBegin()->value), metadata_, edge_name_);
|
||||
}
|
||||
if (static_cast<std::string>(data_.MemberBegin()->name.GetString()) == "$gt")
|
||||
{
|
||||
return std::make_shared<MongoGtFunction>(copyValue(data_.MemberBegin()->value), metadata_, edge_name_);
|
||||
}
|
||||
if (static_cast<std::string>(data_.MemberBegin()->name.GetString()) == "$gte")
|
||||
{
|
||||
return std::make_shared<MongoGteFunction>(copyValue(data_.MemberBegin()->value), metadata_, edge_name_);
|
||||
}
|
||||
if (static_cast<std::string>(data_.MemberBegin()->name.GetString()) == "$ne")
|
||||
{
|
||||
return std::make_shared<MongoNotEqualsFunction>(copyValue(data_.MemberBegin()->value), metadata_, edge_name_);
|
||||
}
|
||||
if (static_cast<std::string>(data_.MemberBegin()->name.GetString()) == "$regex")
|
||||
{
|
||||
return std::make_shared<MongoLikeFunction>(copyValue(data_.MemberBegin()->value), metadata_, edge_name_);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
103
src/Parsers/Mongo/ParserMongoQuery.h
Normal file
103
src/Parsers/Mongo/ParserMongoQuery.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
#include <Parsers/Mongo/Metadata.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
/// Base class for Mongo parsers.
|
||||
/// Contains data, that should be parsed in parseImpl method,
|
||||
/// metadata about query (for example collection),
|
||||
/// edge name for parent edge.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// { quantity: { $lt: 20 } }
|
||||
/// ^
|
||||
/// |
|
||||
/// current vertex
|
||||
///
|
||||
/// For this vertex edge_name = "quantity" and data = { [$lt]: 20 }
|
||||
class IMongoParser
|
||||
{
|
||||
protected:
|
||||
rapidjson::Value data;
|
||||
std::shared_ptr<QueryMetadata> metadata;
|
||||
std::string edge_name;
|
||||
|
||||
public:
|
||||
explicit IMongoParser(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_)
|
||||
: data(std::move(data_)), metadata(metadata_), edge_name(edge_name_)
|
||||
{
|
||||
}
|
||||
|
||||
/// Returns false if data is incorrect and cannot be parsed into node.
|
||||
virtual bool parseImpl(ASTPtr & node) = 0;
|
||||
|
||||
virtual ~IMongoParser() = default;
|
||||
};
|
||||
|
||||
|
||||
/// Creates a parser based on edge name and data.
|
||||
std::shared_ptr<IMongoParser> createParser(
|
||||
rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_, bool literal_as_default = false);
|
||||
|
||||
/// Creates a inversed parsed based on edge name and data.
|
||||
/// Inversed means that mongo syntax have inversed order of elements in tree.
|
||||
/// Example : $lt operator. In mongo syntax it should have structure like { quantity: { $lt: 20 } }
|
||||
/// So tree for this json looks like
|
||||
///
|
||||
/// quantity
|
||||
/// / \
|
||||
/// (operator <) 20
|
||||
///
|
||||
/// But in AST representation looks like
|
||||
///
|
||||
/// (operator <)
|
||||
/// / \
|
||||
/// quantity 20
|
||||
///
|
||||
/// So some operators needs in special parsers
|
||||
std::shared_ptr<IMongoParser>
|
||||
createInversedParser(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_, const std::string & edge_name_);
|
||||
|
||||
|
||||
/// Class to connect mongo and clickhouse parsers
|
||||
class ParserMongoQuery : public IParserBase
|
||||
{
|
||||
private:
|
||||
// These fields are not used when Mongo is disabled at build time.
|
||||
[[maybe_unused]] size_t max_query_size;
|
||||
[[maybe_unused]] size_t max_parser_depth;
|
||||
[[maybe_unused]] size_t max_parser_backtracks;
|
||||
|
||||
rapidjson::Value data;
|
||||
std::shared_ptr<QueryMetadata> metadata;
|
||||
|
||||
public:
|
||||
explicit ParserMongoQuery(size_t max_query_size_, size_t max_parser_depth_, size_t max_parser_backtracks_)
|
||||
: max_query_size(max_query_size_), max_parser_depth(max_parser_depth_), max_parser_backtracks(max_parser_backtracks_)
|
||||
{
|
||||
}
|
||||
|
||||
void setParsingData(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_)
|
||||
{
|
||||
data = data_;
|
||||
metadata = metadata_;
|
||||
}
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "Mongo query"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
104
src/Parsers/Mongo/ParserMongoSelectQuery.cpp
Normal file
104
src/Parsers/Mongo/ParserMongoSelectQuery.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "ParserMongoSelectQuery.h"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTSelectQuery.h>
|
||||
#include <Parsers/ASTTablesInSelectQuery.h>
|
||||
#include <Parsers/ASTAsterisk.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||
#include <Parsers/ASTSubquery.h>
|
||||
#include <Parsers/ASTWithElement.h>
|
||||
#include <Parsers/IParserBase.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoFilter.h>
|
||||
#include <Parsers/Mongo/ParserMongoOrderBy.h>
|
||||
#include <Parsers/Mongo/ParserMongoProjection.h>
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
bool ParserMongoSelectQuery::parseImpl(ASTPtr & node)
|
||||
{
|
||||
auto select_query = std::make_shared<ASTSelectQuery>();
|
||||
|
||||
auto projection = findField(data, "$projection");
|
||||
/// Equals to SELECT * ...
|
||||
if (!projection)
|
||||
{
|
||||
select_query->setExpression(ASTSelectQuery::Expression::SELECT, std::make_shared<ASTExpressionList>());
|
||||
select_query->select()->children.push_back(std::make_shared<ASTAsterisk>());
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Otherwise traverse projection tree to parse projection
|
||||
data.EraseMember("$projection");
|
||||
ASTPtr projection_node;
|
||||
|
||||
auto parser = ParserMongoProjection(std::move(*projection), metadata, "$projection");
|
||||
if (!parser.parseImpl(projection_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
select_query->setExpression(ASTSelectQuery::Expression::SELECT, std::move(projection_node));
|
||||
}
|
||||
|
||||
/// Attach collection to AST.
|
||||
node = select_query;
|
||||
ASTPtr tables = std::make_shared<ASTTablesInSelectQuery>();
|
||||
|
||||
auto table_expression_ast = std::make_shared<ASTTableExpression>();
|
||||
table_expression_ast->children.push_back(std::make_shared<ASTTableIdentifier>(metadata->getCollectionName()));
|
||||
table_expression_ast->database_and_table_name = table_expression_ast->children.back();
|
||||
|
||||
auto tables_in_select_query_element_ast = std::make_shared<ASTTablesInSelectQueryElement>();
|
||||
tables_in_select_query_element_ast->children.push_back(std::move(table_expression_ast));
|
||||
tables_in_select_query_element_ast->table_expression = tables_in_select_query_element_ast->children.back();
|
||||
|
||||
tables->children.push_back(std::move(tables_in_select_query_element_ast));
|
||||
|
||||
select_query->setExpression(ASTSelectQuery::Expression::TABLES, std::move(tables));
|
||||
|
||||
if (metadata->getLimit())
|
||||
{
|
||||
size_t limit_value = *metadata->getLimit();
|
||||
auto literal = std::make_shared<ASTLiteral>(Field(limit_value));
|
||||
select_query->setExpression(ASTSelectQuery::Expression::LIMIT_LENGTH, std::move(literal));
|
||||
}
|
||||
|
||||
if (metadata->getOrderBy())
|
||||
{
|
||||
ASTPtr order_by_node;
|
||||
auto order_by = *metadata->getOrderBy();
|
||||
auto order_by_tree = parseData(order_by.data(), order_by.data() + order_by.size());
|
||||
if (!ParserMongoOrderBy(std::move(order_by_tree), metadata, "").parseImpl(order_by_node))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
select_query->setExpression(ASTSelectQuery::Expression::ORDER_BY, std::move(order_by_node));
|
||||
}
|
||||
|
||||
/// Traverse data tree for WHERE operator
|
||||
ASTPtr where_condition;
|
||||
if (ParserMongoFilter(std::move(data), metadata, "").parseImpl(where_condition))
|
||||
{
|
||||
select_query->setExpression(ASTSelectQuery::Expression::WHERE, std::move(where_condition));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
31
src/Parsers/Mongo/ParserMongoSelectQuery.h
Normal file
31
src/Parsers/Mongo/ParserMongoSelectQuery.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
#include <Parsers/Mongo/Metadata.h>
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
class ParserMongoSelectQuery : public IMongoParser
|
||||
{
|
||||
public:
|
||||
explicit ParserMongoSelectQuery(rapidjson::Value data_, std::shared_ptr<QueryMetadata> metadata_)
|
||||
: IMongoParser(std::move(data_), metadata_, "")
|
||||
{
|
||||
}
|
||||
|
||||
bool parseImpl(ASTPtr & node) override;
|
||||
|
||||
~ParserMongoSelectQuery() override = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
144
src/Parsers/Mongo/Utils.cpp
Normal file
144
src/Parsers/Mongo/Utils.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
#include "Utils.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
std::pair<const char *, const char *> getMetadataSubstring(const char * begin, const char * end)
|
||||
{
|
||||
const char * position = findKth<'('>(begin, end, 1);
|
||||
if (position == end)
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid query: can not parse metadata in query");
|
||||
}
|
||||
return {begin, position};
|
||||
}
|
||||
|
||||
std::pair<const char *, const char *> getSettingsSubstring(const char * begin, const char * end)
|
||||
{
|
||||
const char * position_start = findKth<'('>(begin, end, 1);
|
||||
if (position_start == end)
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid query: can not find settings in query");
|
||||
}
|
||||
|
||||
const char * position_end = findKth<')'>(begin, end, 1);
|
||||
if (position_end == end)
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid query: can not find settings in your query ");
|
||||
}
|
||||
return {position_start + 1, position_end};
|
||||
}
|
||||
|
||||
void validateFirstMetadataArgument(const char * begin, const char * end)
|
||||
{
|
||||
size_t size = end - begin;
|
||||
if (size < 2 || *(end - 1) != 'b' || *(end - 2) != 'd')
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid query: first argument of query should be 'db'");
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<rapidjson::Value> findField(const rapidjson::Value & value, const std::string & key)
|
||||
{
|
||||
for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it)
|
||||
{
|
||||
if (it->name.GetString() == key)
|
||||
{
|
||||
return copyValue(it->value);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
rapidjson::Value parseData(const char * begin, const char * end)
|
||||
{
|
||||
std::string input(begin, end);
|
||||
std::replace(input.begin(), input.end(), '\'', '"');
|
||||
|
||||
rapidjson::Document document;
|
||||
|
||||
if (document.Parse(input.data()).HasParseError())
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Error while parsing json in parseData {}", input);
|
||||
}
|
||||
return copyValue(document);
|
||||
}
|
||||
|
||||
std::optional<size_t> MongoQueryKeyNameExtractor::findPosition(const char * begin, const char * end)
|
||||
{
|
||||
size_t size_str = end - begin;
|
||||
for (size_t i = 0; i < size_str - pattern.size() + 1; ++i)
|
||||
{
|
||||
bool match = true;
|
||||
for (size_t j = 0; j < pattern.size(); ++j)
|
||||
{
|
||||
if (begin[i + j] != pattern[j])
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
if (begin[i + pattern.size()] != '(')
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Incorrect query : after {} should be (", pattern);
|
||||
}
|
||||
return i + pattern.size() + 1;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<int> MongoQueryKeyNameExtractor::extractInt(const char * begin, const char * end)
|
||||
{
|
||||
auto maybe_start_position = findPosition(begin, end);
|
||||
if (!maybe_start_position)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
auto start_position = *maybe_start_position;
|
||||
std::string str_representation;
|
||||
while (begin[start_position] != ')')
|
||||
{
|
||||
if (begin[start_position] < '0' || begin[start_position] > '9')
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Incorrect query : pattern {} should contain only numbers", pattern);
|
||||
}
|
||||
str_representation.push_back(begin[start_position]);
|
||||
++start_position;
|
||||
}
|
||||
return std::stoi(str_representation);
|
||||
}
|
||||
|
||||
std::optional<std::string> MongoQueryKeyNameExtractor::extractString(const char * begin, const char * end)
|
||||
{
|
||||
auto maybe_start_position = findPosition(begin, end);
|
||||
if (!maybe_start_position)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
auto start_position = *maybe_start_position;
|
||||
std::string result;
|
||||
while (begin[start_position] != ')')
|
||||
{
|
||||
result.push_back(begin[start_position]);
|
||||
++start_position;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
81
src/Parsers/Mongo/Utils.h
Normal file
81
src/Parsers/Mongo/Utils.h
Normal file
@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <Common/Exception.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
template <char token>
|
||||
const char * findKth(const char * begin, const char * end, size_t k)
|
||||
{
|
||||
const char * iter = begin;
|
||||
for (size_t i = 0; i < k; ++i)
|
||||
{
|
||||
if (i != 0 && iter != end)
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
while (iter < end && iter[0] != token)
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
if (iter == end)
|
||||
{
|
||||
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid query: there is less than {} tokens {}", k, token);
|
||||
}
|
||||
}
|
||||
return iter;
|
||||
|
||||
}
|
||||
|
||||
std::pair<const char *, const char *> getMetadataSubstring(const char * begin, const char * end);
|
||||
|
||||
std::pair<const char *, const char *> getSettingsSubstring(const char * begin, const char * end);
|
||||
|
||||
void validateFirstMetadataArgument(const char * begin, const char * end);
|
||||
|
||||
template <typename T>
|
||||
rapidjson::Value copyValue(const T & value)
|
||||
{
|
||||
static rapidjson::Document::AllocatorType allocator;
|
||||
|
||||
rapidjson::Value result;
|
||||
result.CopyFrom(value, allocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<rapidjson::Value> findField(const rapidjson::Value & value, const std::string & key);
|
||||
|
||||
rapidjson::Value parseData(const char * begin, const char * end);
|
||||
|
||||
|
||||
class MongoQueryKeyNameExtractor
|
||||
{
|
||||
public:
|
||||
explicit MongoQueryKeyNameExtractor(const std::string & pattern_) : pattern(pattern_) { }
|
||||
|
||||
std::optional<int> extractInt(const char * begin, const char * end);
|
||||
|
||||
std::optional<std::string> extractString(const char * begin, const char * end);
|
||||
|
||||
private:
|
||||
std::optional<size_t> findPosition(const char * begin, const char * end);
|
||||
|
||||
std::string pattern;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
116
src/Parsers/Mongo/parseMongoQuery.cpp
Normal file
116
src/Parsers/Mongo/parseMongoQuery.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "parseMongoQuery.h"
|
||||
|
||||
#include <Parsers/ASTInsertQuery.h>
|
||||
#include <Parsers/IParser.h>
|
||||
|
||||
#include <Parsers/Mongo/ParserMongoQuery.h>
|
||||
#include <Parsers/Mongo/Utils.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
ASTPtr tryParseMongoQuery(
|
||||
IParser & parser,
|
||||
const char *& _out_query_end, // query start as input parameter, query end as output
|
||||
const char *& end,
|
||||
std::string & /*out_error_message*/,
|
||||
bool /*hilite*/,
|
||||
const std::string & /*description*/,
|
||||
bool /*allow_multi_statements*/,
|
||||
size_t max_query_size,
|
||||
size_t max_parser_depth,
|
||||
size_t max_parser_backtracks,
|
||||
bool /*skip_insignificant*/)
|
||||
{
|
||||
Expected expected;
|
||||
ASTPtr res;
|
||||
Tokens token_subquery(_out_query_end, end, max_query_size, true);
|
||||
IParser::Pos token_iterator(token_subquery, static_cast<uint32_t>(max_parser_depth), static_cast<uint32_t>(max_parser_backtracks));
|
||||
std::shared_ptr<QueryMetadata> metadata;
|
||||
|
||||
auto [data_begin, data_end] = getSettingsSubstring(_out_query_end, end);
|
||||
metadata = extractMetadataFromRequest(_out_query_end, end);
|
||||
dynamic_cast<ParserMongoQuery &>(parser).setParsingData(parseData(data_begin, data_end), metadata);
|
||||
|
||||
_out_query_end = findKth<';'>(_out_query_end, end, 1) + 1;
|
||||
const bool parse_res = parser.parse(token_iterator, res, expected);
|
||||
if (!parse_res)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/// Parse query or throw an exception with error message.
|
||||
ASTPtr parseMongoQueryAndMovePosition(
|
||||
IParser & parser,
|
||||
const char *& pos, /// Moved to end of parsed fragment.
|
||||
const char * end,
|
||||
const std::string & description,
|
||||
bool allow_multi_statements,
|
||||
size_t max_query_size,
|
||||
size_t max_parser_depth,
|
||||
size_t max_parser_backtracks)
|
||||
{
|
||||
std::string error_message;
|
||||
ASTPtr res = tryParseMongoQuery(
|
||||
parser,
|
||||
pos,
|
||||
end,
|
||||
error_message,
|
||||
false,
|
||||
description,
|
||||
allow_multi_statements,
|
||||
max_query_size,
|
||||
max_parser_depth,
|
||||
max_parser_backtracks);
|
||||
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
throw Exception::createDeprecated(error_message, ErrorCodes::SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
ASTPtr parseMongoQuery(
|
||||
IParser & parser,
|
||||
const char * begin,
|
||||
const char * end,
|
||||
const std::string & /*description*/,
|
||||
size_t max_query_size,
|
||||
size_t max_parser_depth,
|
||||
size_t max_parser_backtracks)
|
||||
{
|
||||
if (begin == end)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
Expected expected;
|
||||
ASTPtr res;
|
||||
Tokens token_subquery(begin, end, max_query_size, true);
|
||||
auto metadata = extractMetadataFromRequest(begin, end);
|
||||
metadata->add_data_to_query = false;
|
||||
auto [data_begin, data_end] = getSettingsSubstring(begin, end);
|
||||
|
||||
dynamic_cast<ParserMongoQuery &>(parser).setParsingData(parseData(data_begin, data_end), metadata);
|
||||
IParser::Pos token_iterator(token_subquery, static_cast<uint32_t>(max_parser_depth), static_cast<uint32_t>(max_parser_backtracks));
|
||||
const bool parse_res = parser.parse(token_iterator, res, expected);
|
||||
if (!parse_res)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
51
src/Parsers/Mongo/parseMongoQuery.h
Normal file
51
src/Parsers/Mongo/parseMongoQuery.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace Mongo
|
||||
{
|
||||
|
||||
ASTPtr tryParseMongoQuery(
|
||||
IParser & parser,
|
||||
const char *& _out_query_end, // query start as input parameter, query end as output
|
||||
const char *& end,
|
||||
std::string & out_error_message,
|
||||
bool hilite,
|
||||
const std::string & description,
|
||||
bool allow_multi_statements,
|
||||
size_t max_query_size,
|
||||
size_t max_parser_depth,
|
||||
size_t max_parser_backtracks,
|
||||
bool skip_insignificant = true);
|
||||
|
||||
|
||||
/// Parse query or throw an exception with error message.
|
||||
ASTPtr parseMongoQueryAndMovePosition(
|
||||
IParser & parser,
|
||||
const char *& pos, /// Moved to end of parsed fragment.
|
||||
const char * end,
|
||||
const std::string & description,
|
||||
bool allow_multi_statements,
|
||||
size_t max_query_size,
|
||||
size_t max_parser_depth,
|
||||
size_t max_parser_backtracks);
|
||||
|
||||
|
||||
ASTPtr parseMongoQuery(
|
||||
IParser & parser,
|
||||
const char * begin,
|
||||
const char * end,
|
||||
const std::string & description,
|
||||
size_t max_query_size,
|
||||
size_t max_parser_depth,
|
||||
size_t max_parser_backtracks);
|
||||
|
||||
}
|
||||
|
||||
}
|
112
tests/queries/0_stateless/03214_mongo_queries.reference
Normal file
112
tests/queries/0_stateless/03214_mongo_queries.reference
Normal file
@ -0,0 +1,112 @@
|
||||
1 2 ac
|
||||
8 6 gh
|
||||
2 9 ij
|
||||
3 4 kl
|
||||
5 7 mn
|
||||
6 1 qr
|
||||
10 12 st
|
||||
11 14 uv
|
||||
13 15 wx
|
||||
14 13 ab
|
||||
16 11 yz
|
||||
7 3 efaaaa
|
||||
9 8 op
|
||||
4 5 b
|
||||
1 2 ac
|
||||
2 9 ij
|
||||
1 2 ac
|
||||
1 2 ac
|
||||
3 4 kl
|
||||
1 2 ac
|
||||
1 2 ac
|
||||
1 2 ac
|
||||
1 2 ac
|
||||
1 2 ac
|
||||
14 13 ab
|
||||
1 2 ac
|
||||
7 3 efaaaa
|
||||
1 2 ac
|
||||
1 2 ac
|
||||
2 9 ij
|
||||
3 4 kl
|
||||
4 5 b
|
||||
5 7 mn
|
||||
6 1 qr
|
||||
7 3 efaaaa
|
||||
8 6 gh
|
||||
9 8 op
|
||||
10 12 st
|
||||
11 14 uv
|
||||
13 15 wx
|
||||
14 13 ab
|
||||
16 11 yz
|
||||
7
|
||||
1
|
||||
8
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
9
|
||||
10
|
||||
11
|
||||
13
|
||||
16
|
||||
14
|
||||
6
|
||||
7 10
|
||||
1 3
|
||||
2 11
|
||||
8 14
|
||||
4 9
|
||||
5 12
|
||||
3 7
|
||||
9 17
|
||||
6 7
|
||||
10 22
|
||||
11 25
|
||||
14 27
|
||||
16 27
|
||||
13 28
|
||||
1 2
|
||||
8 48
|
||||
5 35
|
||||
2 18
|
||||
10 120
|
||||
3 12
|
||||
6 6
|
||||
9 72
|
||||
13 195
|
||||
11 154
|
||||
4 20
|
||||
16 176
|
||||
14 182
|
||||
7 21
|
||||
1 0.5
|
||||
7 2.3333333333333335
|
||||
8 1.3333333333333333
|
||||
2 0.2222222222222222
|
||||
3 0.75
|
||||
5 0.7142857142857143
|
||||
9 1.125
|
||||
11 0.7857142857142857
|
||||
6 6
|
||||
10 0.8333333333333334
|
||||
13 0.8666666666666667
|
||||
14 1.0769230769230769
|
||||
4 0.8
|
||||
16 1.4545454545454546
|
||||
7 28
|
||||
1 3
|
||||
8 56
|
||||
4 24
|
||||
5 40
|
||||
9 81
|
||||
16 192
|
||||
3 15
|
||||
13 208
|
||||
11 165
|
||||
10 130
|
||||
2 20
|
||||
14 196
|
||||
6 12
|
44
tests/queries/0_stateless/03214_mongo_queries.sql
Normal file
44
tests/queries/0_stateless/03214_mongo_queries.sql
Normal file
@ -0,0 +1,44 @@
|
||||
SET dialect='clickhouse';
|
||||
|
||||
DROP TABLE IF EXISTS test;
|
||||
CREATE TABLE test
|
||||
(
|
||||
c0 Int32,
|
||||
c1 Int32,
|
||||
c2 String,
|
||||
)
|
||||
ENGINE = Memory;
|
||||
INSERT INTO test(c0, c1, c2) VALUES (1, 2, 'ac');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (4, 5, 'b');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (7, 3, 'efaaaa');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (8, 6, 'gh');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (2, 9, 'ij');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (3, 4, 'kl');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (5, 7, 'mn');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (9, 8, 'op');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (6, 1, 'qr');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (10, 12, 'st');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (11, 14, 'uv');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (13, 15, 'wx');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (16, 11, 'yz');
|
||||
INSERT INTO test(c0, c1, c2) VALUES (14, 13, 'ab');
|
||||
|
||||
SET dialect='mongo';
|
||||
db.test.find({});
|
||||
db.test.find({"c0" : 1});
|
||||
db.test.find({"c0" : 2});
|
||||
db.test.find({"c0" : 1, "c1" : 2});
|
||||
db.test.find({"$or" : [{"c0" : 1}, {"c0" : 3}]});
|
||||
db.test.find({"c0" : 1, "c1" : {"$lt" : 3}});
|
||||
db.test.find({"c0" : 1, "c1" : {"$lte" : 3}});
|
||||
db.test.find({"c0" : 1, "c1" : {"$gt" : 1}});
|
||||
db.test.find({"c0" : 1, "c1" : {"$gte" : 2}});
|
||||
db.test.find({"c0" : 1, "c1" : {"$ne" : 0}});
|
||||
db.test.find({"c2" : {"$regex" : "%a%"}});
|
||||
db.test.find({}).limit(1);
|
||||
db.test.find({}).sort({"c0" : 1});
|
||||
db.test.find({"$projection" : {"b0" : "c0"}});
|
||||
db.test.find({"$projection" : {"b0" : "c0", "b1" : {"$add" : ["c0", "c1"]}}});
|
||||
db.test.find({"$projection" : {"b0" : "c0", "b1" : {"$mul" : ["c0", "c1"]}}});
|
||||
db.test.find({"$projection" : {"b0" : "c0", "b1" : {"$div" : ["c0", "c1"]}}});
|
||||
db.test.find({"$projection" : {"b0" : "c0", "b1" : {"$add" : ["c0", {"$mul" : ["c0", "c1"]}]}}});
|
Loading…
Reference in New Issue
Block a user