Skip to content

Commit

Permalink
Merge pull request #13 from ClibMouse/Kusto-phase2
Browse files Browse the repository at this point in the history
Kusto phase2
  • Loading branch information
kashwy authored Jun 24, 2022
2 parents 189d0ff + 61ba208 commit f65b5d2
Show file tree
Hide file tree
Showing 47 changed files with 5,341 additions and 10 deletions.
31 changes: 25 additions & 6 deletions src/Client/ClientBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
#include <IO/CompressionMethod.h>
#include <Client/InternalTextLogs.h>
#include <boost/algorithm/string/replace.hpp>

#include <Parsers/Kusto/ParserKQLStatement.h>

namespace fs = std::filesystem;
using namespace std::literals;
Expand Down Expand Up @@ -299,29 +299,48 @@ void ClientBase::setupSignalHandler()

ASTPtr ClientBase::parseQuery(const char *& pos, const char * end, bool allow_multi_statements) const
{
ParserQuery parser(end, global_context->getSettings().allow_settings_after_format_in_insert);
std::shared_ptr<IParserBase> parser;
ParserKQLStatement kql_parser(end, global_context->getSettings().allow_settings_after_format_in_insert);
ASTPtr res;

const auto & settings = global_context->getSettingsRef();
size_t max_length = 0;

auto begin = pos;

if (!allow_multi_statements)
max_length = settings.max_query_size;

const String & sql_dialect = settings.sql_dialect;

if (sql_dialect == "kusto")
parser = std::make_shared<ParserKQLStatement>(end, global_context->getSettings().allow_settings_after_format_in_insert);
else
parser = std::make_shared<ParserQuery>(end, global_context->getSettings().allow_settings_after_format_in_insert);

if (is_interactive || ignore_error)
{
String message;
res = tryParseQuery(parser, pos, end, message, true, "", allow_multi_statements, max_length, settings.max_parser_depth);
res = tryParseQuery(*parser, pos, end, message, true, "", allow_multi_statements, max_length, settings.max_parser_depth);

if (!res)
{
std::cerr << std::endl << message << std::endl << std::endl;
return nullptr;
if (sql_dialect != "kusto")
res = tryParseQuery(kql_parser, begin, end, message, true, "", allow_multi_statements, max_length, settings.max_parser_depth);

if (!res)
{
std::cerr << std::endl << message << std::endl << std::endl;
return nullptr;
}
}
}
else
{
res = parseQueryAndMovePosition(parser, pos, end, "", allow_multi_statements, max_length, settings.max_parser_depth);
res = parseQueryAndMovePosition(*parser, pos, end, "", allow_multi_statements, max_length, settings.max_parser_depth);

if (!res && sql_dialect != "kusto")
res = parseQueryAndMovePosition(kql_parser, begin, end, "", allow_multi_statements, max_length, settings.max_parser_depth);
}

if (is_interactive)
Expand Down
1 change: 1 addition & 0 deletions src/Core/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static constexpr UInt64 operator""_GiB(unsigned long long value)
*/

#define COMMON_SETTINGS(M) \
M(String, sql_dialect, "clickhouse", "Which SQL dialect will be used to parse query", 0)\
M(UInt64, min_compress_block_size, 65536, "The actual size of the block to compress, if the uncompressed data less than max_compress_block_size is no less than this value and no less than the volume of data for one mark.", 0) \
M(UInt64, max_compress_block_size, 1048576, "The maximum size of blocks of uncompressed data before compressing for writing to a table.", 0) \
M(UInt64, max_block_size, DEFAULT_BLOCK_SIZE, "Maximum block size for reading", 0) \
Expand Down
32 changes: 29 additions & 3 deletions src/Interpreters/executeQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@

#include <random>

#include <Parsers/Kusto/ParserKQLStatement.h>

namespace ProfileEvents
{
Expand Down Expand Up @@ -406,10 +407,35 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
String query_table;
try
{
ParserQuery parser(end, settings.allow_settings_after_format_in_insert);
const String & sql_dialect = settings.sql_dialect;
assert(sql_dialect == "clickhouse" || sql_dialect == "kusto" || sql_dialect == "kusto_auto");

/// TODO: parser should fail early when max_query_size limit is reached.
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
if (sql_dialect == "kusto" && !internal)
{
ParserKQLStatement parser(end, settings.allow_settings_after_format_in_insert);
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
}
else if (sql_dialect == "kusto_auto" && !internal)
{
try {
ParserQuery parser(end, settings.allow_settings_after_format_in_insert);

/// TODO: parser should fail early when max_query_size limit is reached.
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
}
catch(...)
{
ParserKQLStatement parser(end, settings.allow_settings_after_format_in_insert);
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
}
}
else
{
ParserQuery parser(end, settings.allow_settings_after_format_in_insert);

/// TODO: parser should fail early when max_query_size limit is reached.
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
}

if (auto txn = context->getCurrentTransaction())
{
Expand Down
2 changes: 2 additions & 0 deletions src/Parsers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ include("${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake")
add_headers_and_sources(clickhouse_parsers .)
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 ./Kusto/KustoFunctions)
add_library(clickhouse_parsers ${clickhouse_parsers_headers} ${clickhouse_parsers_sources})
target_link_libraries(clickhouse_parsers PUBLIC clickhouse_common_io clickhouse_common_access string_utils)

Expand Down
134 changes: 134 additions & 0 deletions src/Parsers/Kusto/KustoFunctions/IParserKQLFunction.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include <Parsers/IParserBase.h>
#include <Parsers/ParserSetQuery.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/Kusto/ParserKQLQuery.h>
#include <Parsers/Kusto/ParserKQLStatement.h>
#include <Parsers/Kusto/KustoFunctions/IParserKQLFunction.h>
#include <Parsers/Kusto/KustoFunctions/KQLDateTimeFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLStringFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLDynamicFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLCastingFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLAggregationFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLTimeSeriesFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLIPFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLBinaryFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLGeneralFunctions.h>
#include <Parsers/Kusto/KustoFunctions/KQLFunctionFactory.h>
#include <Parsers/Kusto/ParserKQLOperators.h>

namespace DB
{

namespace ErrorCodes
{
extern const int SYNTAX_ERROR;
}


bool IParserKQLFunction::convert(String &out,IParser::Pos &pos)
{
return wrapConvertImpl(pos, IncreaseDepthTag{}, [&]
{
bool res = convertImpl(out,pos);
if (!res)
out = "";
return res;
});
}

bool IParserKQLFunction::directMapping(String &out,IParser::Pos &pos,const String &ch_fn)
{
std::vector<String> arguments;

String fn_name = getKQLFunctionName(pos);

if (fn_name.empty())
return false;

String res;
auto begin = pos;
++pos;
while (!pos->isEnd() && pos->type != TokenType::PipeMark && pos->type != TokenType::Semicolon)
{
String argument = getConvertedArgument(fn_name,pos);
arguments.push_back(argument);

if (pos->type == TokenType::ClosingRoundBracket)
{
for (auto arg : arguments)
{
if (res.empty())
res = ch_fn + "(" + arg;
else
res = res + ", "+ arg;
}
res += ")";

out = res;
return true;
}
++pos;
}

pos = begin;
return false;
}

String IParserKQLFunction::getConvertedArgument(const String &fn_name, IParser::Pos &pos)
{
String converted_arg;
std::vector<String> tokens;
std::unique_ptr<IParserKQLFunction> fun;

if (pos->type == TokenType::ClosingRoundBracket)
return converted_arg;

if (pos->isEnd() || pos->type == TokenType::PipeMark || pos->type == TokenType::Semicolon)
throw Exception("Syntax error near " + fn_name, ErrorCodes::SYNTAX_ERROR);

while (!pos->isEnd() && pos->type != TokenType::PipeMark && pos->type != TokenType::Semicolon)
{
String token = String(pos->begin,pos->end);
String new_token;
if (!KQLOperators().convert(tokens,pos))
{
if (pos->type == TokenType::BareWord )
{
String converted;
fun = KQLFunctionFactory::get(token);
if ( fun && fun->convert(converted,pos))
tokens.push_back(converted);
else
tokens.push_back(token);
}
else if (pos->type == TokenType::Comma || pos->type == TokenType::ClosingRoundBracket)
{
break;
}
else
tokens.push_back(token);
}
++pos;
if (pos->type == TokenType::Comma || pos->type == TokenType::ClosingRoundBracket)
break;
}
for (auto token : tokens)
converted_arg = converted_arg + token +" ";

return converted_arg;
}

String IParserKQLFunction::getKQLFunctionName(IParser::Pos &pos)
{
String fn_name = String(pos->begin, pos->end);
++pos;
if (pos->type != TokenType::OpeningRoundBracket)
{
--pos;
return "";
}
return fn_name;
}

}
42 changes: 42 additions & 0 deletions src/Parsers/Kusto/KustoFunctions/IParserKQLFunction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <Parsers/IParserBase.h>
#include <Parsers/Kusto/KustoFunctions/IParserKQLFunction.h>
namespace DB
{
class IParserKQLFunction
{
public:
template <typename F>
ALWAYS_INLINE static bool wrapConvertImpl(IParser::Pos & pos, const F & func)
{
IParser::Pos begin = pos;
bool res = func();
if (!res)
pos = begin;
return res;
}
struct IncreaseDepthTag {};
template <typename F>
ALWAYS_INLINE static bool wrapConvertImpl(IParser::Pos & pos, IncreaseDepthTag, const F & func)
{
IParser::Pos begin = pos;
pos.increaseDepth();
bool res = func();
pos.decreaseDepth();
if (!res)
pos = begin;
return res;
}
bool convert(String &out,IParser::Pos &pos);
virtual const char * getName() const = 0;
virtual ~IParserKQLFunction() = default;
protected:
virtual bool convertImpl(String &out,IParser::Pos &pos) = 0;
static bool directMapping(String &out,IParser::Pos &pos,const String &ch_fn);
static String getConvertedArgument(const String &fn_name, IParser::Pos &pos);
static String getKQLFunctionName(IParser::Pos &pos);
};

}

Loading

0 comments on commit f65b5d2

Please sign in to comment.