ANTLR4 Grammar for ClickHouse and new parser (#11298)

This commit is contained in:
Ivan 2020-12-04 05:15:44 +03:00 committed by GitHub
parent 6a48d25b74
commit 315ff4f0d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
312 changed files with 38835 additions and 1571 deletions

11
.gitignore vendored
View File

@ -125,4 +125,15 @@ website/package-lock.json
# Toolchains # Toolchains
/cmake/toolchain/* /cmake/toolchain/*
# ANTLR extension cache
.antlr
# ANTLR generated files
/src/Parsers/New/*.interp
/src/Parsers/New/*.tokens
/src/Parsers/New/ClickHouseParserBaseVisitor.*
# pytest-profiling
/prof
*.iml *.iml

3
.gitmodules vendored
View File

@ -172,6 +172,9 @@
[submodule "contrib/fmtlib"] [submodule "contrib/fmtlib"]
path = contrib/fmtlib path = contrib/fmtlib
url = https://github.com/fmtlib/fmt.git url = https://github.com/fmtlib/fmt.git
[submodule "contrib/antlr4-runtime"]
path = contrib/antlr4-runtime
url = https://github.com/ClickHouse-Extras/antlr4-runtime.git
[submodule "contrib/sentry-native"] [submodule "contrib/sentry-native"]
path = contrib/sentry-native path = contrib/sentry-native
url = https://github.com/ClickHouse-Extras/sentry-native.git url = https://github.com/ClickHouse-Extras/sentry-native.git

View File

@ -257,6 +257,8 @@ if (WITH_COVERAGE AND COMPILER_GCC)
set(WITHOUT_COVERAGE "-fno-profile-arcs -fno-test-coverage") set(WITHOUT_COVERAGE "-fno-profile-arcs -fno-test-coverage")
endif() endif()
set(COMPILER_FLAGS "${COMPILER_FLAGS}")
set (CMAKE_BUILD_COLOR_MAKEFILE ON) set (CMAKE_BUILD_COLOR_MAKEFILE ON)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS} ${PLATFORM_EXTRA_CXX_FLAG} ${COMMON_WARNING_FLAGS} ${CXX_WARNING_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS} ${PLATFORM_EXTRA_CXX_FLAG} ${COMMON_WARNING_FLAGS} ${CXX_WARNING_FLAGS}")
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 ${CMAKE_CXX_FLAGS_ADD}") set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 ${CMAKE_CXX_FLAGS_ADD}")

View File

@ -76,12 +76,6 @@
# define NO_SANITIZE_THREAD # define NO_SANITIZE_THREAD
#endif #endif
#if defined __GNUC__ && !defined __clang__
# define OPTIMIZE(x) __attribute__((__optimize__(x)))
#else
# define OPTIMIZE(x)
#endif
/// A macro for suppressing warnings about unused variables or function results. /// A macro for suppressing warnings about unused variables or function results.
/// Useful for structured bindings which have no standard way to declare this. /// Useful for structured bindings which have no standard way to declare this.
#define UNUSED(...) (void)(__VA_ARGS__) #define UNUSED(...) (void)(__VA_ARGS__)

View File

@ -24,7 +24,7 @@ option (WEVERYTHING "Enable -Weverything option with some exceptions." ON)
# Control maximum size of stack frames. It can be important if the code is run in fibers with small stack size. # Control maximum size of stack frames. It can be important if the code is run in fibers with small stack size.
# Only in release build because debug has too large stack frames. # Only in release build because debug has too large stack frames.
if ((NOT CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG") AND (NOT SANITIZE) AND (NOT CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")) if ((NOT CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG") AND (NOT SANITIZE) AND (NOT CMAKE_CXX_COMPILER_ID MATCHES "AppleClang"))
add_warning(frame-larger-than=32768) add_warning(frame-larger-than=65536)
endif () endif ()
if (COMPILER_CLANG) if (COMPILER_CLANG)

View File

@ -21,6 +21,7 @@ endif()
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL 1) set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL 1)
add_subdirectory (antlr4-runtime-cmake)
add_subdirectory (boost-cmake) add_subdirectory (boost-cmake)
add_subdirectory (cctz-cmake) add_subdirectory (cctz-cmake)
add_subdirectory (consistent-hashing-sumbur) add_subdirectory (consistent-hashing-sumbur)

1
contrib/antlr4-runtime vendored Submodule

@ -0,0 +1 @@
Subproject commit a2fa7b76e2ee16d2ad955e9214a90bbf79da66fc

View File

@ -0,0 +1,156 @@
set (LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/antlr4-runtime)
set (SRCS
${LIBRARY_DIR}/ANTLRErrorListener.cpp
${LIBRARY_DIR}/ANTLRErrorStrategy.cpp
${LIBRARY_DIR}/ANTLRFileStream.cpp
${LIBRARY_DIR}/ANTLRInputStream.cpp
${LIBRARY_DIR}/atn/AbstractPredicateTransition.cpp
${LIBRARY_DIR}/atn/ActionTransition.cpp
${LIBRARY_DIR}/atn/AmbiguityInfo.cpp
${LIBRARY_DIR}/atn/ArrayPredictionContext.cpp
${LIBRARY_DIR}/atn/ATN.cpp
${LIBRARY_DIR}/atn/ATNConfig.cpp
${LIBRARY_DIR}/atn/ATNConfigSet.cpp
${LIBRARY_DIR}/atn/ATNDeserializationOptions.cpp
${LIBRARY_DIR}/atn/ATNDeserializer.cpp
${LIBRARY_DIR}/atn/ATNSerializer.cpp
${LIBRARY_DIR}/atn/ATNSimulator.cpp
${LIBRARY_DIR}/atn/ATNState.cpp
${LIBRARY_DIR}/atn/AtomTransition.cpp
${LIBRARY_DIR}/atn/BasicBlockStartState.cpp
${LIBRARY_DIR}/atn/BasicState.cpp
${LIBRARY_DIR}/atn/BlockEndState.cpp
${LIBRARY_DIR}/atn/BlockStartState.cpp
${LIBRARY_DIR}/atn/ContextSensitivityInfo.cpp
${LIBRARY_DIR}/atn/DecisionEventInfo.cpp
${LIBRARY_DIR}/atn/DecisionInfo.cpp
${LIBRARY_DIR}/atn/DecisionState.cpp
${LIBRARY_DIR}/atn/EmptyPredictionContext.cpp
${LIBRARY_DIR}/atn/EpsilonTransition.cpp
${LIBRARY_DIR}/atn/ErrorInfo.cpp
${LIBRARY_DIR}/atn/LexerAction.cpp
${LIBRARY_DIR}/atn/LexerActionExecutor.cpp
${LIBRARY_DIR}/atn/LexerATNConfig.cpp
${LIBRARY_DIR}/atn/LexerATNSimulator.cpp
${LIBRARY_DIR}/atn/LexerChannelAction.cpp
${LIBRARY_DIR}/atn/LexerCustomAction.cpp
${LIBRARY_DIR}/atn/LexerIndexedCustomAction.cpp
${LIBRARY_DIR}/atn/LexerModeAction.cpp
${LIBRARY_DIR}/atn/LexerMoreAction.cpp
${LIBRARY_DIR}/atn/LexerPopModeAction.cpp
${LIBRARY_DIR}/atn/LexerPushModeAction.cpp
${LIBRARY_DIR}/atn/LexerSkipAction.cpp
${LIBRARY_DIR}/atn/LexerTypeAction.cpp
${LIBRARY_DIR}/atn/LL1Analyzer.cpp
${LIBRARY_DIR}/atn/LookaheadEventInfo.cpp
${LIBRARY_DIR}/atn/LoopEndState.cpp
${LIBRARY_DIR}/atn/NotSetTransition.cpp
${LIBRARY_DIR}/atn/OrderedATNConfigSet.cpp
${LIBRARY_DIR}/atn/ParseInfo.cpp
${LIBRARY_DIR}/atn/ParserATNSimulator.cpp
${LIBRARY_DIR}/atn/PlusBlockStartState.cpp
${LIBRARY_DIR}/atn/PlusLoopbackState.cpp
${LIBRARY_DIR}/atn/PrecedencePredicateTransition.cpp
${LIBRARY_DIR}/atn/PredicateEvalInfo.cpp
${LIBRARY_DIR}/atn/PredicateTransition.cpp
${LIBRARY_DIR}/atn/PredictionContext.cpp
${LIBRARY_DIR}/atn/PredictionMode.cpp
${LIBRARY_DIR}/atn/ProfilingATNSimulator.cpp
${LIBRARY_DIR}/atn/RangeTransition.cpp
${LIBRARY_DIR}/atn/RuleStartState.cpp
${LIBRARY_DIR}/atn/RuleStopState.cpp
${LIBRARY_DIR}/atn/RuleTransition.cpp
${LIBRARY_DIR}/atn/SemanticContext.cpp
${LIBRARY_DIR}/atn/SetTransition.cpp
${LIBRARY_DIR}/atn/SingletonPredictionContext.cpp
${LIBRARY_DIR}/atn/StarBlockStartState.cpp
${LIBRARY_DIR}/atn/StarLoopbackState.cpp
${LIBRARY_DIR}/atn/StarLoopEntryState.cpp
${LIBRARY_DIR}/atn/TokensStartState.cpp
${LIBRARY_DIR}/atn/Transition.cpp
${LIBRARY_DIR}/atn/WildcardTransition.cpp
${LIBRARY_DIR}/BailErrorStrategy.cpp
${LIBRARY_DIR}/BaseErrorListener.cpp
${LIBRARY_DIR}/BufferedTokenStream.cpp
${LIBRARY_DIR}/CharStream.cpp
${LIBRARY_DIR}/CommonToken.cpp
${LIBRARY_DIR}/CommonTokenFactory.cpp
${LIBRARY_DIR}/CommonTokenStream.cpp
${LIBRARY_DIR}/ConsoleErrorListener.cpp
${LIBRARY_DIR}/DefaultErrorStrategy.cpp
${LIBRARY_DIR}/dfa/DFA.cpp
${LIBRARY_DIR}/dfa/DFASerializer.cpp
${LIBRARY_DIR}/dfa/DFAState.cpp
${LIBRARY_DIR}/dfa/LexerDFASerializer.cpp
${LIBRARY_DIR}/DiagnosticErrorListener.cpp
${LIBRARY_DIR}/Exceptions.cpp
${LIBRARY_DIR}/FailedPredicateException.cpp
${LIBRARY_DIR}/InputMismatchException.cpp
${LIBRARY_DIR}/InterpreterRuleContext.cpp
${LIBRARY_DIR}/IntStream.cpp
${LIBRARY_DIR}/Lexer.cpp
${LIBRARY_DIR}/LexerInterpreter.cpp
${LIBRARY_DIR}/LexerNoViableAltException.cpp
${LIBRARY_DIR}/ListTokenSource.cpp
${LIBRARY_DIR}/misc/InterpreterDataReader.cpp
${LIBRARY_DIR}/misc/Interval.cpp
${LIBRARY_DIR}/misc/IntervalSet.cpp
${LIBRARY_DIR}/misc/MurmurHash.cpp
${LIBRARY_DIR}/misc/Predicate.cpp
${LIBRARY_DIR}/NoViableAltException.cpp
${LIBRARY_DIR}/Parser.cpp
${LIBRARY_DIR}/ParserInterpreter.cpp
${LIBRARY_DIR}/ParserRuleContext.cpp
${LIBRARY_DIR}/ProxyErrorListener.cpp
${LIBRARY_DIR}/RecognitionException.cpp
${LIBRARY_DIR}/Recognizer.cpp
${LIBRARY_DIR}/RuleContext.cpp
${LIBRARY_DIR}/RuleContextWithAltNum.cpp
${LIBRARY_DIR}/RuntimeMetaData.cpp
${LIBRARY_DIR}/support/Any.cpp
${LIBRARY_DIR}/support/Arrays.cpp
${LIBRARY_DIR}/support/CPPUtils.cpp
${LIBRARY_DIR}/support/guid.cpp
${LIBRARY_DIR}/support/StringUtils.cpp
${LIBRARY_DIR}/Token.cpp
${LIBRARY_DIR}/TokenSource.cpp
${LIBRARY_DIR}/TokenStream.cpp
${LIBRARY_DIR}/TokenStreamRewriter.cpp
${LIBRARY_DIR}/tree/ErrorNode.cpp
${LIBRARY_DIR}/tree/ErrorNodeImpl.cpp
${LIBRARY_DIR}/tree/IterativeParseTreeWalker.cpp
${LIBRARY_DIR}/tree/ParseTree.cpp
${LIBRARY_DIR}/tree/ParseTreeListener.cpp
${LIBRARY_DIR}/tree/ParseTreeVisitor.cpp
${LIBRARY_DIR}/tree/ParseTreeWalker.cpp
${LIBRARY_DIR}/tree/pattern/Chunk.cpp
${LIBRARY_DIR}/tree/pattern/ParseTreeMatch.cpp
${LIBRARY_DIR}/tree/pattern/ParseTreePattern.cpp
${LIBRARY_DIR}/tree/pattern/ParseTreePatternMatcher.cpp
${LIBRARY_DIR}/tree/pattern/RuleTagToken.cpp
${LIBRARY_DIR}/tree/pattern/TagChunk.cpp
${LIBRARY_DIR}/tree/pattern/TextChunk.cpp
${LIBRARY_DIR}/tree/pattern/TokenTagToken.cpp
${LIBRARY_DIR}/tree/TerminalNode.cpp
${LIBRARY_DIR}/tree/TerminalNodeImpl.cpp
${LIBRARY_DIR}/tree/Trees.cpp
${LIBRARY_DIR}/tree/xpath/XPath.cpp
${LIBRARY_DIR}/tree/xpath/XPathElement.cpp
${LIBRARY_DIR}/tree/xpath/XPathLexer.cpp
${LIBRARY_DIR}/tree/xpath/XPathLexerErrorListener.cpp
${LIBRARY_DIR}/tree/xpath/XPathRuleAnywhereElement.cpp
${LIBRARY_DIR}/tree/xpath/XPathRuleElement.cpp
${LIBRARY_DIR}/tree/xpath/XPathTokenAnywhereElement.cpp
${LIBRARY_DIR}/tree/xpath/XPathTokenElement.cpp
${LIBRARY_DIR}/tree/xpath/XPathWildcardAnywhereElement.cpp
${LIBRARY_DIR}/tree/xpath/XPathWildcardElement.cpp
${LIBRARY_DIR}/UnbufferedCharStream.cpp
${LIBRARY_DIR}/UnbufferedTokenStream.cpp
${LIBRARY_DIR}/Vocabulary.cpp
${LIBRARY_DIR}/WritableToken.cpp
)
add_library (antlr4-runtime ${SRCS})
target_include_directories (antlr4-runtime SYSTEM PUBLIC ${LIBRARY_DIR})

View File

@ -131,6 +131,7 @@ function clone_submodules
cd "$FASTTEST_SOURCE" cd "$FASTTEST_SOURCE"
SUBMODULES_TO_UPDATE=( SUBMODULES_TO_UPDATE=(
contrib/antlr4-runtime
contrib/boost contrib/boost
contrib/zlib-ng contrib/zlib-ng
contrib/libxml2 contrib/libxml2

View File

@ -1,8 +1,8 @@
#include <AggregateFunctions/parseAggregateFunctionParameters.h> #include <AggregateFunctions/parseAggregateFunctionParameters.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>
#include <Common/typeid_cast.h>
#include <Core/Defines.h>
namespace DB namespace DB
@ -25,6 +25,13 @@ Array getAggregateFunctionParametersArray(const ASTPtr & expression_list, const
for (size_t i = 0; i < parameters.size(); ++i) for (size_t i = 0; i < parameters.size(); ++i)
{ {
const auto * literal = parameters[i]->as<ASTLiteral>(); const auto * literal = parameters[i]->as<ASTLiteral>();
ASTPtr func_literal;
if (!literal)
if (const auto * func = parameters[i]->as<ASTFunction>())
if ((func_literal = func->toLiteral()))
literal = func_literal->as<ASTLiteral>();
if (!literal) if (!literal)
{ {
throw Exception( throw Exception(

View File

@ -6,18 +6,6 @@ if (USE_CLANG_TIDY)
set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}") set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}")
endif () endif ()
if(COMPILER_PIPE)
set(MAX_COMPILER_MEMORY 2500)
else()
set(MAX_COMPILER_MEMORY 1500)
endif()
if(MAKE_STATIC_LIBRARIES)
set(MAX_LINKER_MEMORY 3500)
else()
set(MAX_LINKER_MEMORY 2500)
endif()
include(../cmake/limit_jobs.cmake)
set (CONFIG_VERSION ${CMAKE_CURRENT_BINARY_DIR}/Common/config_version.h) set (CONFIG_VERSION ${CMAKE_CURRENT_BINARY_DIR}/Common/config_version.h)
set (CONFIG_COMMON ${CMAKE_CURRENT_BINARY_DIR}/Common/config.h) set (CONFIG_COMMON ${CMAKE_CURRENT_BINARY_DIR}/Common/config.h)
@ -49,6 +37,7 @@ add_subdirectory (Dictionaries)
add_subdirectory (Disks) add_subdirectory (Disks)
add_subdirectory (Storages) add_subdirectory (Storages)
add_subdirectory (Parsers) add_subdirectory (Parsers)
add_subdirectory (Parsers/New)
add_subdirectory (IO) add_subdirectory (IO)
add_subdirectory (Functions) add_subdirectory (Functions)
add_subdirectory (Interpreters) add_subdirectory (Interpreters)
@ -186,12 +175,12 @@ endif()
if (MAKE_STATIC_LIBRARIES OR NOT SPLIT_SHARED_LIBRARIES) if (MAKE_STATIC_LIBRARIES OR NOT SPLIT_SHARED_LIBRARIES)
add_library (dbms STATIC ${dbms_headers} ${dbms_sources}) add_library (dbms STATIC ${dbms_headers} ${dbms_sources})
target_link_libraries (dbms PRIVATE jemalloc libdivide ${DBMS_COMMON_LIBRARIES}) target_link_libraries (dbms PRIVATE clickhouse_parsers_new jemalloc libdivide ${DBMS_COMMON_LIBRARIES})
set (all_modules dbms) set (all_modules dbms)
else() else()
add_library (dbms SHARED ${dbms_headers} ${dbms_sources}) add_library (dbms SHARED ${dbms_headers} ${dbms_sources})
target_link_libraries (dbms PUBLIC ${all_modules} ${DBMS_COMMON_LIBRARIES}) target_link_libraries (dbms PUBLIC ${all_modules} ${DBMS_COMMON_LIBRARIES})
target_link_libraries (clickhouse_interpreters PRIVATE jemalloc libdivide) target_link_libraries (clickhouse_interpreters PRIVATE clickhouse_parsers_new jemalloc libdivide)
list (APPEND all_modules dbms) list (APPEND all_modules dbms)
# force all split libs to be linked # force all split libs to be linked
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-as-needed") set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-as-needed")

View File

@ -799,9 +799,8 @@ namespace MySQLReplication
break; break;
} }
case WRITE_ROWS_EVENT_V1: case WRITE_ROWS_EVENT_V1:
case WRITE_ROWS_EVENT_V2: case WRITE_ROWS_EVENT_V2: {
{ if (doReplicate())
if (do_replicate())
event = std::make_shared<WriteRowsEvent>(table_map, std::move(event_header)); event = std::make_shared<WriteRowsEvent>(table_map, std::move(event_header));
else else
event = std::make_shared<DryRunEvent>(std::move(event_header)); event = std::make_shared<DryRunEvent>(std::move(event_header));
@ -810,9 +809,8 @@ namespace MySQLReplication
break; break;
} }
case DELETE_ROWS_EVENT_V1: case DELETE_ROWS_EVENT_V1:
case DELETE_ROWS_EVENT_V2: case DELETE_ROWS_EVENT_V2: {
{ if (doReplicate())
if (do_replicate())
event = std::make_shared<DeleteRowsEvent>(table_map, std::move(event_header)); event = std::make_shared<DeleteRowsEvent>(table_map, std::move(event_header));
else else
event = std::make_shared<DryRunEvent>(std::move(event_header)); event = std::make_shared<DryRunEvent>(std::move(event_header));
@ -821,9 +819,8 @@ namespace MySQLReplication
break; break;
} }
case UPDATE_ROWS_EVENT_V1: case UPDATE_ROWS_EVENT_V1:
case UPDATE_ROWS_EVENT_V2: case UPDATE_ROWS_EVENT_V2: {
{ if (doReplicate())
if (do_replicate())
event = std::make_shared<UpdateRowsEvent>(table_map, std::move(event_header)); event = std::make_shared<UpdateRowsEvent>(table_map, std::move(event_header));
else else
event = std::make_shared<DryRunEvent>(std::move(event_header)); event = std::make_shared<DryRunEvent>(std::move(event_header));

View File

@ -549,7 +549,7 @@ namespace MySQLReplication
std::shared_ptr<TableMapEvent> table_map; std::shared_ptr<TableMapEvent> table_map;
size_t checksum_signature_length = 4; size_t checksum_signature_length = 4;
inline bool do_replicate() { return (replicate_do_db.empty() || table_map->schema == replicate_do_db); } inline bool doReplicate() { return (replicate_do_db.empty() || table_map->schema == replicate_do_db); }
}; };
} }

View File

@ -399,6 +399,8 @@ class IColumn;
M(Bool, enable_global_with_statement, false, "Propagate WITH statements to UNION queries and all subqueries", 0) \ M(Bool, enable_global_with_statement, false, "Propagate WITH statements to UNION queries and all subqueries", 0) \
M(Bool, aggregate_functions_null_for_empty, false, "Rewrite all aggregate functions in a query, adding -OrNull suffix to them", 0) \ M(Bool, aggregate_functions_null_for_empty, false, "Rewrite all aggregate functions in a query, adding -OrNull suffix to them", 0) \
\ \
M(Bool, use_antlr_parser, false, "Parse incoming queries using ANTLR-generated parser", 0) \
\
/** Obsolete settings that do nothing but left for compatibility reasons. Remove each one after half a year of obsolescence. */ \ /** Obsolete settings that do nothing but left for compatibility reasons. Remove each one after half a year of obsolescence. */ \
\ \
M(UInt64, max_memory_usage_for_all_queries, 0, "Obsolete. Will be removed after 2020-10-20", 0) \ M(UInt64, max_memory_usage_for_all_queries, 0, "Obsolete. Will be removed after 2020-10-20", 0) \

View File

@ -357,20 +357,23 @@ static DataTypePtr create(const ASTPtr & arguments)
throw Exception("Unexpected level of parameters to aggregate function", ErrorCodes::SYNTAX_ERROR); throw Exception("Unexpected level of parameters to aggregate function", ErrorCodes::SYNTAX_ERROR);
function_name = parametric->name; function_name = parametric->name;
const ASTs & parameters = parametric->arguments->children; if (parametric->arguments)
params_row.resize(parameters.size());
for (size_t i = 0; i < parameters.size(); ++i)
{ {
const auto * literal = parameters[i]->as<ASTLiteral>(); const ASTs & parameters = parametric->arguments->children;
if (!literal) params_row.resize(parameters.size());
throw Exception(
ErrorCodes::PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS,
"Parameters to aggregate functions must be literals. "
"Got parameter '{}' for function '{}'",
parameters[i]->formatForErrorMessage(), function_name);
params_row[i] = literal->value; for (size_t i = 0; i < parameters.size(); ++i)
{
const auto * literal = parameters[i]->as<ASTLiteral>();
if (!literal)
throw Exception(
ErrorCodes::PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS,
"Parameters to aggregate functions must be literals. "
"Got parameter '{}' for function '{}'",
parameters[i]->formatForErrorMessage(), function_name);
params_row[i] = literal->value;
}
} }
} }
else if (auto opt_name = tryGetIdentifierName(arguments->children[0])) else if (auto opt_name = tryGetIdentifierName(arguments->children[0]))

View File

@ -72,20 +72,24 @@ static std::pair<DataTypePtr, DataTypeCustomDescPtr> create(const ASTPtr & argum
throw Exception("Unexpected level of parameters to aggregate function", ErrorCodes::SYNTAX_ERROR); throw Exception("Unexpected level of parameters to aggregate function", ErrorCodes::SYNTAX_ERROR);
function_name = parametric->name; function_name = parametric->name;
const ASTs & parameters = parametric->arguments->as<ASTExpressionList &>().children; if (parametric->arguments)
params_row.resize(parameters.size());
for (size_t i = 0; i < parameters.size(); ++i)
{ {
const ASTLiteral * lit = parameters[i]->as<ASTLiteral>(); const ASTs & parameters = parametric->arguments->as<ASTExpressionList &>().children;
if (!lit) params_row.resize(parameters.size());
throw Exception(
ErrorCodes::PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS,
"Parameters to aggregate functions must be literals. "
"Got parameter '{}' for function '{}'",
parameters[i]->formatForErrorMessage(), function_name);
params_row[i] = lit->value; for (size_t i = 0; i < parameters.size(); ++i)
{
const ASTLiteral * lit = parameters[i]->as<ASTLiteral>();
if (!lit)
throw Exception(
ErrorCodes::PARAMETERS_TO_AGGREGATE_FUNCTIONS_MUST_BE_LITERALS,
"Parameters to aggregate functions must be literals. "
"Got parameter '{}' for function '{}'",
parameters[i]->formatForErrorMessage(),
function_name);
params_row[i] = lit->value;
}
} }
} }
else if (auto opt_name = tryGetIdentifierName(arguments->children[0])) else if (auto opt_name = tryGetIdentifierName(arguments->children[0]))

View File

@ -99,38 +99,40 @@ void buildLayoutConfiguration(
root->appendChild(layout_element); root->appendChild(layout_element);
AutoPtr<Element> layout_type_element(doc->createElement(layout->layout_type)); AutoPtr<Element> layout_type_element(doc->createElement(layout->layout_type));
layout_element->appendChild(layout_type_element); layout_element->appendChild(layout_type_element);
for (const auto & param : layout->parameters->children)
{ if (layout->parameters)
const ASTPair * pair = param->as<ASTPair>(); for (const auto & param : layout->parameters->children)
if (!pair)
{ {
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "Dictionary layout parameters must be key/value pairs, got '{}' instead", const ASTPair * pair = param->as<ASTPair>();
param->formatForErrorMessage()); if (!pair)
{
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "Dictionary layout parameters must be key/value pairs, got '{}' instead",
param->formatForErrorMessage());
}
const ASTLiteral * value_literal = pair->second->as<ASTLiteral>();
if (!value_literal)
{
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS,
"Dictionary layout parameter value must be a literal, got '{}' instead",
pair->second->formatForErrorMessage());
}
const auto value_field = value_literal->value;
if (value_field.getType() != Field::Types::UInt64
&& value_field.getType() != Field::Types::String)
{
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS,
"Dictionary layout parameter value must be an UInt64 or String, got '{}' instead",
value_field.getTypeName());
}
AutoPtr<Element> layout_type_parameter_element(doc->createElement(pair->first));
AutoPtr<Text> value_to_append(doc->createTextNode(toString(value_field)));
layout_type_parameter_element->appendChild(value_to_append);
layout_type_element->appendChild(layout_type_parameter_element);
} }
const ASTLiteral * value_literal = pair->second->as<ASTLiteral>();
if (!value_literal)
{
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS,
"Dictionary layout parameter value must be a literal, got '{}' instead",
pair->second->formatForErrorMessage());
}
const auto value_field = value_literal->value;
if (value_field.getType() != Field::Types::UInt64
&& value_field.getType() != Field::Types::String)
{
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS,
"Dictionary layout parameter value must be an UInt64 or String, got '{}' instead",
value_field.getTypeName());
}
AutoPtr<Element> layout_type_parameter_element(doc->createElement(pair->first));
AutoPtr<Text> value_to_append(doc->createTextNode(toString(value_field)));
layout_type_parameter_element->appendChild(value_to_append);
layout_type_element->appendChild(layout_type_parameter_element);
}
} }
/* /*

View File

@ -141,16 +141,16 @@ struct NumericArraySource : public ArraySourceImpl<NumericArraySource<T>>
/// The methods can be virtual or not depending on the template parameter. See IStringSource. /// The methods can be virtual or not depending on the template parameter. See IStringSource.
#if !__clang__ #if !__clang__
#pragma GCC diagnostic push # pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-override" # pragma GCC diagnostic ignored "-Wsuggest-override"
#elif __clang_major__ >= 11 #elif __clang_major__ >= 11
#pragma GCC diagnostic push # pragma GCC diagnostic push
#ifdef HAS_SUGGEST_OVERRIDE # ifdef HAS_SUGGEST_OVERRIDE
#pragma GCC diagnostic ignored "-Wsuggest-override" # pragma GCC diagnostic ignored "-Wsuggest-override"
#endif # endif
#ifdef HAS_SUGGEST_DESTRUCTOR_OVERRIDE # ifdef HAS_SUGGEST_DESTRUCTOR_OVERRIDE
#pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # pragma GCC diagnostic ignored "-Wsuggest-destructor-override"
#endif # endif
#endif #endif
template <typename Base> template <typename Base>
@ -234,7 +234,7 @@ struct ConstSource : public Base
}; };
#if !__clang__ || __clang_major__ >= 11 #if !__clang__ || __clang_major__ >= 11
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
struct StringSource struct StringSource
@ -355,9 +355,9 @@ struct UTF8StringSource : public StringSource
Slice getSliceFromLeft(size_t offset) const Slice getSliceFromLeft(size_t offset) const
{ {
auto begin = &elements[prev_offset]; const auto * begin = &elements[prev_offset];
auto end = elements.data() + offsets[row_num] - 1; const auto * end = elements.data() + offsets[row_num] - 1;
auto res_begin = skipCodePointsForward(begin, offset, end); const auto * res_begin = skipCodePointsForward(begin, offset, end);
if (res_begin >= end) if (res_begin >= end)
return {begin, 0}; return {begin, 0};
@ -367,14 +367,14 @@ struct UTF8StringSource : public StringSource
Slice getSliceFromLeft(size_t offset, size_t length) const Slice getSliceFromLeft(size_t offset, size_t length) const
{ {
auto begin = &elements[prev_offset]; const auto * begin = &elements[prev_offset];
auto end = elements.data() + offsets[row_num] - 1; const auto * end = elements.data() + offsets[row_num] - 1;
auto res_begin = skipCodePointsForward(begin, offset, end); const auto * res_begin = skipCodePointsForward(begin, offset, end);
if (res_begin >= end) if (res_begin >= end)
return {begin, 0}; return {begin, 0};
auto res_end = skipCodePointsForward(res_begin, length, end); const auto * res_end = skipCodePointsForward(res_begin, length, end);
if (res_end >= end) if (res_end >= end)
return {res_begin, size_t(end - res_begin)}; return {res_begin, size_t(end - res_begin)};
@ -384,19 +384,19 @@ struct UTF8StringSource : public StringSource
Slice getSliceFromRight(size_t offset) const Slice getSliceFromRight(size_t offset) const
{ {
auto begin = &elements[prev_offset]; const auto * begin = &elements[prev_offset];
auto end = elements.data() + offsets[row_num] - 1; const auto * end = elements.data() + offsets[row_num] - 1;
auto res_begin = skipCodePointsBackward(end, offset, begin); const auto * res_begin = skipCodePointsBackward(end, offset, begin);
return {res_begin, size_t(end - res_begin)}; return {res_begin, size_t(end - res_begin)};
} }
Slice getSliceFromRight(size_t offset, size_t length) const Slice getSliceFromRight(size_t offset, size_t length) const
{ {
auto begin = &elements[prev_offset]; const auto * begin = &elements[prev_offset];
auto end = elements.data() + offsets[row_num] - 1; const auto * end = elements.data() + offsets[row_num] - 1;
auto res_begin = skipCodePointsBackward(end, offset, begin); const auto * res_begin = skipCodePointsBackward(end, offset, begin);
auto res_end = skipCodePointsForward(res_begin, length, end); const auto * res_end = skipCodePointsForward(res_begin, length, end);
if (res_end >= end) if (res_end >= end)
return {res_begin, size_t(end - res_begin)}; return {res_begin, size_t(end - res_begin)};
@ -495,7 +495,7 @@ struct IStringSource
virtual bool isEnd() const = 0; virtual bool isEnd() const = 0;
virtual size_t getSizeForReserve() const = 0; virtual size_t getSizeForReserve() const = 0;
virtual Slice getWhole() const = 0; virtual Slice getWhole() const = 0;
virtual ~IStringSource() {} virtual ~IStringSource() = default;
}; };

View File

@ -757,39 +757,102 @@ void ActionsMatcher::visit(const ASTFunction & node, const ASTPtr & ast, Data &
/// If the function has an argument-lambda expression, you need to determine its type before the recursive call. /// If the function has an argument-lambda expression, you need to determine its type before the recursive call.
bool has_lambda_arguments = false; bool has_lambda_arguments = false;
size_t num_arguments = node.arguments->children.size();
for (size_t arg = 0; arg < num_arguments; ++arg) if (node.arguments)
{ {
auto & child = node.arguments->children[arg]; size_t num_arguments = node.arguments->children.size();
for (size_t arg = 0; arg < num_arguments; ++arg)
const auto * function = child->as<ASTFunction>();
const auto * identifier = child->as<ASTIdentifier>();
if (function && function->name == "lambda")
{ {
/// If the argument is a lambda expression, just remember its approximate type. auto & child = node.arguments->children[arg];
if (function->arguments->children.size() != 2)
throw Exception("lambda requires two arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
const auto * lambda_args_tuple = function->arguments->children.at(0)->as<ASTFunction>(); const auto * function = child->as<ASTFunction>();
const auto * identifier = child->as<ASTIdentifier>();
if (!lambda_args_tuple || lambda_args_tuple->name != "tuple") if (function && function->name == "lambda")
throw Exception("First argument of lambda must be a tuple", ErrorCodes::TYPE_MISMATCH);
has_lambda_arguments = true;
argument_types.emplace_back(std::make_shared<DataTypeFunction>(DataTypes(lambda_args_tuple->arguments->children.size())));
/// Select the name in the next cycle.
argument_names.emplace_back();
}
else if (function && function->name == "untuple")
{
auto columns = doUntuple(function, data);
if (columns.empty())
continue;
for (const auto & column : columns)
{ {
if (auto name_type = getNameAndTypeFromAST(column, data)) /// If the argument is a lambda expression, just remember its approximate type.
if (function->arguments->children.size() != 2)
throw Exception("lambda requires two arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
const auto * lambda_args_tuple = function->arguments->children.at(0)->as<ASTFunction>();
if (!lambda_args_tuple || lambda_args_tuple->name != "tuple")
throw Exception("First argument of lambda must be a tuple", ErrorCodes::TYPE_MISMATCH);
has_lambda_arguments = true;
argument_types.emplace_back(std::make_shared<DataTypeFunction>(DataTypes(lambda_args_tuple->arguments->children.size())));
/// Select the name in the next cycle.
argument_names.emplace_back();
}
else if (function && function->name == "untuple")
{
auto columns = doUntuple(function, data);
if (columns.empty())
continue;
for (const auto & column : columns)
{
if (auto name_type = getNameAndTypeFromAST(column, data))
{
argument_types.push_back(name_type->type);
argument_names.push_back(name_type->name);
}
else
arguments_present = false;
}
node.arguments->children.erase(node.arguments->children.begin() + arg);
node.arguments->children.insert(node.arguments->children.begin() + arg, columns.begin(), columns.end());
num_arguments += columns.size() - 1;
arg += columns.size() - 1;
}
else if (checkFunctionIsInOrGlobalInOperator(node) && arg == 1 && prepared_set)
{
ColumnWithTypeAndName column;
column.type = std::make_shared<DataTypeSet>();
/// If the argument is a set given by an enumeration of values (so, the set was already built), give it a unique name,
/// so that sets with the same literal representation do not fuse together (they can have different types).
if (!prepared_set->empty())
column.name = data.getUniqueName("__set");
else
column.name = child->getColumnName();
if (!data.hasColumn(column.name))
{
auto column_set = ColumnSet::create(1, prepared_set);
/// If prepared_set is not empty, we have a set made with literals.
/// Create a const ColumnSet to make constant folding work
if (!prepared_set->empty())
column.column = ColumnConst::create(std::move(column_set), 1);
else
column.column = std::move(column_set);
data.addColumn(column);
}
argument_types.push_back(column.type);
argument_names.push_back(column.name);
}
else if (identifier && (functionIsJoinGet(node.name) || functionIsDictGet(node.name)) && arg == 0)
{
auto table_id = IdentifierSemantic::extractDatabaseAndTable(*identifier);
table_id = data.context.resolveStorageID(table_id, Context::ResolveOrdinary);
auto column_string = ColumnString::create();
column_string->insert(table_id.getDatabaseName() + "." + table_id.getTableName());
ColumnWithTypeAndName column(
ColumnConst::create(std::move(column_string), 1),
std::make_shared<DataTypeString>(),
data.getUniqueName("__" + node.name));
data.addColumn(column);
argument_types.push_back(column.type);
argument_names.push_back(column.name);
}
else
{
/// If the argument is not a lambda expression, call it recursively and find out its type.
visit(child, data);
if (auto name_type = getNameAndTypeFromAST(child, data))
{ {
argument_types.push_back(name_type->type); argument_types.push_back(name_type->type);
argument_names.push_back(name_type->name); argument_names.push_back(name_type->name);
@ -797,125 +860,66 @@ void ActionsMatcher::visit(const ASTFunction & node, const ASTPtr & ast, Data &
else else
arguments_present = false; arguments_present = false;
} }
node.arguments->children.erase(node.arguments->children.begin() + arg);
node.arguments->children.insert(node.arguments->children.begin() + arg, columns.begin(), columns.end());
num_arguments += columns.size() - 1;
arg += columns.size() - 1;
} }
else if (checkFunctionIsInOrGlobalInOperator(node) && arg == 1 && prepared_set)
if (data.only_consts && !arguments_present)
return;
if (has_lambda_arguments && !data.only_consts)
{ {
ColumnWithTypeAndName column; function_builder->getLambdaArgumentTypes(argument_types);
column.type = std::make_shared<DataTypeSet>();
/// If the argument is a set given by an enumeration of values (so, the set was already built), give it a unique name, /// Call recursively for lambda expressions.
/// so that sets with the same literal representation do not fuse together (they can have different types). for (size_t i = 0; i < node.arguments->children.size(); ++i)
if (!prepared_set->empty())
column.name = data.getUniqueName("__set");
else
column.name = child->getColumnName();
if (!data.hasColumn(column.name))
{ {
auto column_set = ColumnSet::create(1, prepared_set); ASTPtr child = node.arguments->children[i];
/// If prepared_set is not empty, we have a set made with literals.
/// Create a const ColumnSet to make constant folding work
if (!prepared_set->empty())
column.column = ColumnConst::create(std::move(column_set), 1);
else
column.column = std::move(column_set);
data.addColumn(column);
}
argument_types.push_back(column.type); const auto * lambda = child->as<ASTFunction>();
argument_names.push_back(column.name); if (lambda && lambda->name == "lambda")
}
else if (identifier && (functionIsJoinGet(node.name) || functionIsDictGet(node.name)) && arg == 0)
{
auto table_id = IdentifierSemantic::extractDatabaseAndTable(*identifier);
table_id = data.context.resolveStorageID(table_id, Context::ResolveOrdinary);
auto column_string = ColumnString::create();
column_string->insert(table_id.getDatabaseName() + "." + table_id.getTableName());
ColumnWithTypeAndName column(
ColumnConst::create(std::move(column_string), 1),
std::make_shared<DataTypeString>(),
data.getUniqueName("__" + node.name));
data.addColumn(column);
argument_types.push_back(column.type);
argument_names.push_back(column.name);
}
else
{
/// If the argument is not a lambda expression, call it recursively and find out its type.
visit(child, data);
if (auto name_type = getNameAndTypeFromAST(child, data))
{
argument_types.push_back(name_type->type);
argument_names.push_back(name_type->name);
}
else
arguments_present = false;
}
}
if (data.only_consts && !arguments_present)
return;
if (has_lambda_arguments && !data.only_consts)
{
function_builder->getLambdaArgumentTypes(argument_types);
/// Call recursively for lambda expressions.
for (size_t i = 0; i < node.arguments->children.size(); ++i)
{
ASTPtr child = node.arguments->children[i];
const auto * lambda = child->as<ASTFunction>();
if (lambda && lambda->name == "lambda")
{
const DataTypeFunction * lambda_type = typeid_cast<const DataTypeFunction *>(argument_types[i].get());
const auto * lambda_args_tuple = lambda->arguments->children.at(0)->as<ASTFunction>();
const ASTs & lambda_arg_asts = lambda_args_tuple->arguments->children;
NamesAndTypesList lambda_arguments;
for (size_t j = 0; j < lambda_arg_asts.size(); ++j)
{ {
auto opt_arg_name = tryGetIdentifierName(lambda_arg_asts[j]); const DataTypeFunction * lambda_type = typeid_cast<const DataTypeFunction *>(argument_types[i].get());
if (!opt_arg_name) const auto * lambda_args_tuple = lambda->arguments->children.at(0)->as<ASTFunction>();
throw Exception("lambda argument declarations must be identifiers", ErrorCodes::TYPE_MISMATCH); const ASTs & lambda_arg_asts = lambda_args_tuple->arguments->children;
NamesAndTypesList lambda_arguments;
lambda_arguments.emplace_back(*opt_arg_name, lambda_type->getArgumentTypes()[j]); for (size_t j = 0; j < lambda_arg_asts.size(); ++j)
{
auto opt_arg_name = tryGetIdentifierName(lambda_arg_asts[j]);
if (!opt_arg_name)
throw Exception("lambda argument declarations must be identifiers", ErrorCodes::TYPE_MISMATCH);
lambda_arguments.emplace_back(*opt_arg_name, lambda_type->getArgumentTypes()[j]);
}
data.actions_stack.pushLevel(lambda_arguments);
visit(lambda->arguments->children.at(1), data);
auto lambda_dag = data.actions_stack.popLevel();
String result_name = lambda->arguments->children.at(1)->getColumnName();
lambda_dag->removeUnusedActions(Names(1, result_name));
auto lambda_actions = std::make_shared<ExpressionActions>(lambda_dag);
DataTypePtr result_type = lambda_actions->getSampleBlock().getByName(result_name).type;
Names captured;
Names required = lambda_actions->getRequiredColumns();
for (const auto & required_arg : required)
if (findColumn(required_arg, lambda_arguments) == lambda_arguments.end())
captured.push_back(required_arg);
/// We can not name `getColumnName()`,
/// because it does not uniquely define the expression (the types of arguments can be different).
String lambda_name = data.getUniqueName("__lambda");
auto function_capture = std::make_unique<FunctionCaptureOverloadResolver>(
lambda_actions, captured, lambda_arguments, result_type, result_name);
auto function_capture_adapter = std::make_shared<FunctionOverloadResolverAdaptor>(std::move(function_capture));
data.addFunction(function_capture_adapter, captured, lambda_name);
argument_types[i] = std::make_shared<DataTypeFunction>(lambda_type->getArgumentTypes(), result_type);
argument_names[i] = lambda_name;
} }
data.actions_stack.pushLevel(lambda_arguments);
visit(lambda->arguments->children.at(1), data);
auto lambda_dag = data.actions_stack.popLevel();
String result_name = lambda->arguments->children.at(1)->getColumnName();
lambda_dag->removeUnusedActions(Names(1, result_name));
auto lambda_actions = std::make_shared<ExpressionActions>(lambda_dag);
DataTypePtr result_type = lambda_actions->getSampleBlock().getByName(result_name).type;
Names captured;
Names required = lambda_actions->getRequiredColumns();
for (const auto & required_arg : required)
if (findColumn(required_arg, lambda_arguments) == lambda_arguments.end())
captured.push_back(required_arg);
/// We can not name `getColumnName()`,
/// because it does not uniquely define the expression (the types of arguments can be different).
String lambda_name = data.getUniqueName("__lambda");
auto function_capture = std::make_unique<FunctionCaptureOverloadResolver>(
lambda_actions, captured, lambda_arguments, result_type, result_name);
auto function_capture_adapter = std::make_shared<FunctionOverloadResolverAdaptor>(std::move(function_capture));
data.addFunction(function_capture_adapter, captured, lambda_name);
argument_types[i] = std::make_shared<DataTypeFunction>(lambda_type->getArgumentTypes(), result_type);
argument_names[i] = lambda_name;
} }
} }
} }

View File

@ -97,10 +97,10 @@ public:
function_node->name == "any" || function_node->name == "anyLast")) function_node->name == "any" || function_node->name == "anyLast"))
{ {
KeepAggregateFunctionVisitor::Data keep_data{data.group_by_keys, false}; KeepAggregateFunctionVisitor::Data keep_data{data.group_by_keys, false};
KeepAggregateFunctionVisitor(keep_data).visit(function_node->arguments); if (function_node->arguments) KeepAggregateFunctionVisitor(keep_data).visit(function_node->arguments);
/// Place argument of an aggregate function instead of function /// Place argument of an aggregate function instead of function
if (!keep_data.keep_aggregator && !function_node->arguments->children.empty()) if (!keep_data.keep_aggregator && function_node->arguments && !function_node->arguments->children.empty())
{ {
String alias = function_node->alias; String alias = function_node->alias;
ast = (function_node->arguments->children[0])->clone(); ast = (function_node->arguments->children[0])->clone();

View File

@ -20,7 +20,7 @@ namespace
const ASTFunction * getInternalFunction(const ASTFunction & func) const ASTFunction * getInternalFunction(const ASTFunction & func)
{ {
if (func.arguments->children.size() == 1) if (func.arguments && func.arguments->children.size() == 1)
return func.arguments->children[0]->as<ASTFunction>(); return func.arguments->children[0]->as<ASTFunction>();
return nullptr; return nullptr;
} }

View File

@ -1412,9 +1412,9 @@ BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & cont
if (const auto * query_alter = query_ptr->as<ASTAlterQuery>()) if (const auto * query_alter = query_ptr->as<ASTAlterQuery>())
{ {
for (const auto & command : query_alter->command_list->commands) for (const auto & command : query_alter->command_list->children)
{ {
if (!isSupportedAlterType(command->type)) if (!isSupportedAlterType(command->as<ASTAlterCommand&>().type))
throw Exception("Unsupported type of ALTER query", ErrorCodes::NOT_IMPLEMENTED); throw Exception("Unsupported type of ALTER query", ErrorCodes::NOT_IMPLEMENTED);
} }
} }

View File

@ -423,11 +423,11 @@ bool ExpressionAnalyzer::makeAggregateDescriptions(ActionsDAGPtr & actions)
for (const ASTFunction * node : aggregates()) for (const ASTFunction * node : aggregates())
{ {
AggregateDescription aggregate; AggregateDescription aggregate;
getRootActionsNoMakeSet(node->arguments, true, actions); if (node->arguments) getRootActionsNoMakeSet(node->arguments, true, actions);
aggregate.column_name = node->getColumnName(); aggregate.column_name = node->getColumnName();
const ASTs & arguments = node->arguments->children; const ASTs & arguments = node->arguments ? node->arguments->children : ASTs();
aggregate.argument_names.resize(arguments.size()); aggregate.argument_names.resize(arguments.size());
DataTypes types(arguments.size()); DataTypes types(arguments.size());
@ -820,8 +820,9 @@ void SelectQueryExpressionAnalyzer::appendAggregateFunctionsArguments(Expression
/// TODO: data.aggregates -> aggregates() /// TODO: data.aggregates -> aggregates()
for (const ASTFunction * node : data.aggregates) for (const ASTFunction * node : data.aggregates)
for (auto & argument : node->arguments->children) if (node->arguments)
getRootActions(argument, only_types, step.actions()); for (auto & argument : node->arguments->children)
getRootActions(argument, only_types, step.actions());
} }
bool SelectQueryExpressionAnalyzer::appendHaving(ExpressionActionsChain & chain, bool only_types) bool SelectQueryExpressionAnalyzer::appendHaving(ExpressionActionsChain & chain, bool only_types)

View File

@ -105,7 +105,7 @@ public:
{ {
if (auto * function_node = ast->as<ASTFunction>()) if (auto * function_node = ast->as<ASTFunction>())
{ {
if (!(function_node->arguments->children.empty())) if (function_node->arguments && !function_node->arguments->children.empty())
visit(function_node, data); visit(function_node, data);
} }
} }

View File

@ -56,8 +56,9 @@ BlockIO InterpreterAlterQuery::execute()
PartitionCommands partition_commands; PartitionCommands partition_commands;
MutationCommands mutation_commands; MutationCommands mutation_commands;
LiveViewCommands live_view_commands; LiveViewCommands live_view_commands;
for (ASTAlterCommand * command_ast : alter.command_list->commands) for (const auto & child : alter.command_list->children)
{ {
auto * command_ast = child->as<ASTAlterCommand>();
if (auto alter_command = AlterCommand::parse(command_ast)) if (auto alter_command = AlterCommand::parse(command_ast))
alter_commands.emplace_back(std::move(*alter_command)); alter_commands.emplace_back(std::move(*alter_command));
else if (auto partition_command = PartitionCommand::parse(command_ast)) else if (auto partition_command = PartitionCommand::parse(command_ast))
@ -124,8 +125,8 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccess() const
{ {
AccessRightsElements required_access; AccessRightsElements required_access;
const auto & alter = query_ptr->as<ASTAlterQuery &>(); const auto & alter = query_ptr->as<ASTAlterQuery &>();
for (ASTAlterCommand * command : alter.command_list->commands) for (const auto & child : alter.command_list->children)
boost::range::push_back(required_access, getRequiredAccessForCommand(*command, alter.database, alter.table)); boost::range::push_back(required_access, getRequiredAccessForCommand(child->as<ASTAlterCommand&>(), alter.database, alter.table));
return required_access; return required_access;
} }

View File

@ -130,6 +130,7 @@ BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
auto engine = std::make_shared<ASTFunction>(); auto engine = std::make_shared<ASTFunction>();
auto storage = std::make_shared<ASTStorage>(); auto storage = std::make_shared<ASTStorage>();
engine->name = old_style_database ? "Ordinary" : "Atomic"; engine->name = old_style_database ? "Ordinary" : "Atomic";
engine->no_empty_args = true;
storage->set(storage->engine, engine); storage->set(storage->engine, engine);
create.set(create.storage, storage); create.set(create.storage, storage);
} }
@ -600,6 +601,7 @@ void InterpreterCreateQuery::setEngine(ASTCreateQuery & create) const
{ {
auto engine_ast = std::make_shared<ASTFunction>(); auto engine_ast = std::make_shared<ASTFunction>();
engine_ast->name = "Memory"; engine_ast->name = "Memory";
engine_ast->no_empty_args = true;
auto storage_ast = std::make_shared<ASTStorage>(); auto storage_ast = std::make_shared<ASTStorage>();
storage_ast->set(storage_ast->engine, engine_ast); storage_ast->set(storage_ast->engine, engine_ast);
create.set(create.storage, storage_ast); create.set(create.storage, storage_ast);

View File

@ -87,8 +87,7 @@ public:
return; return;
/// TODO: monotonicity for functions of several arguments /// TODO: monotonicity for functions of several arguments
auto arguments = ast_function.arguments; if (!ast_function.arguments || ast_function.arguments->children.size() != 1)
if (arguments->children.size() != 1)
{ {
data.reject(); data.reject();
return; return;

View File

@ -442,10 +442,10 @@ ASTPtr MutationsInterpreter::prepare(bool dry_run)
auto type_literal = std::make_shared<ASTLiteral>(columns_desc.getPhysical(column).type->getName()); auto type_literal = std::make_shared<ASTLiteral>(columns_desc.getPhysical(column).type->getName());
const auto & update_expr = kv.second; const auto & update_expr = kv.second;
auto updated_column = makeASTFunction("CAST", auto updated_column = makeASTFunction("cast",
makeASTFunction("if", makeASTFunction("if",
getPartitionAndPredicateExpressionForMutationCommand(command), getPartitionAndPredicateExpressionForMutationCommand(command),
makeASTFunction("CAST", makeASTFunction("cast",
update_expr->clone(), update_expr->clone(),
type_literal), type_literal),
std::make_shared<ASTIdentifier>(column)), std::make_shared<ASTIdentifier>(column)),

View File

@ -478,7 +478,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
auto rewritten_rename_query = std::make_shared<ASTRenameQuery>(); auto rewritten_rename_query = std::make_shared<ASTRenameQuery>();
rewritten_alter_query->database = mapped_to_database; rewritten_alter_query->database = mapped_to_database;
rewritten_alter_query->table = alter_query.table; rewritten_alter_query->table = alter_query.table;
rewritten_alter_query->set(rewritten_alter_query->command_list, std::make_shared<ASTAlterCommandList>()); rewritten_alter_query->set(rewritten_alter_query->command_list, std::make_shared<ASTExpressionList>());
String default_after_column; String default_after_column;
for (const auto & command_query : alter_query.command_list->children) for (const auto & command_query : alter_query.command_list->children)
@ -542,7 +542,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
} }
rewritten_command->children.push_back(rewritten_command->col_decl); rewritten_command->children.push_back(rewritten_command->col_decl);
rewritten_alter_query->command_list->add(rewritten_command); rewritten_alter_query->command_list->children.push_back(rewritten_command);
} }
} }
else if (alter_command->type == MySQLParser::ASTAlterCommand::DROP_COLUMN) else if (alter_command->type == MySQLParser::ASTAlterCommand::DROP_COLUMN)
@ -550,7 +550,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
auto rewritten_command = std::make_shared<ASTAlterCommand>(); auto rewritten_command = std::make_shared<ASTAlterCommand>();
rewritten_command->type = ASTAlterCommand::DROP_COLUMN; rewritten_command->type = ASTAlterCommand::DROP_COLUMN;
rewritten_command->column = std::make_shared<ASTIdentifier>(alter_command->column_name); rewritten_command->column = std::make_shared<ASTIdentifier>(alter_command->column_name);
rewritten_alter_query->command_list->add(rewritten_command); rewritten_alter_query->command_list->children.push_back(rewritten_command);
} }
else if (alter_command->type == MySQLParser::ASTAlterCommand::RENAME_COLUMN) else if (alter_command->type == MySQLParser::ASTAlterCommand::RENAME_COLUMN)
{ {
@ -561,7 +561,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
rewritten_command->type = ASTAlterCommand::RENAME_COLUMN; rewritten_command->type = ASTAlterCommand::RENAME_COLUMN;
rewritten_command->column = std::make_shared<ASTIdentifier>(alter_command->old_name); rewritten_command->column = std::make_shared<ASTIdentifier>(alter_command->old_name);
rewritten_command->rename_to = std::make_shared<ASTIdentifier>(alter_command->column_name); rewritten_command->rename_to = std::make_shared<ASTIdentifier>(alter_command->column_name);
rewritten_alter_query->command_list->add(rewritten_command); rewritten_alter_query->command_list->children.push_back(rewritten_command);
} }
} }
else if (alter_command->type == MySQLParser::ASTAlterCommand::MODIFY_COLUMN) else if (alter_command->type == MySQLParser::ASTAlterCommand::MODIFY_COLUMN)
@ -590,7 +590,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
rewritten_command->children.push_back(rewritten_command->column); rewritten_command->children.push_back(rewritten_command->column);
} }
rewritten_alter_query->command_list->add(rewritten_command); rewritten_alter_query->command_list->children.push_back(rewritten_command);
} }
if (!alter_command->old_name.empty() && alter_command->old_name != new_column_name) if (!alter_command->old_name.empty() && alter_command->old_name != new_column_name)
@ -599,7 +599,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
rewritten_command->type = ASTAlterCommand::RENAME_COLUMN; rewritten_command->type = ASTAlterCommand::RENAME_COLUMN;
rewritten_command->column = std::make_shared<ASTIdentifier>(alter_command->old_name); rewritten_command->column = std::make_shared<ASTIdentifier>(alter_command->old_name);
rewritten_command->rename_to = std::make_shared<ASTIdentifier>(new_column_name); rewritten_command->rename_to = std::make_shared<ASTIdentifier>(new_column_name);
rewritten_alter_query->command_list->add(rewritten_command); rewritten_alter_query->command_list->children.push_back(rewritten_command);
} }
} }
else if (alter_command->type == MySQLParser::ASTAlterCommand::RENAME_TABLE) else if (alter_command->type == MySQLParser::ASTAlterCommand::RENAME_TABLE)
@ -624,7 +624,7 @@ ASTs InterpreterAlterImpl::getRewrittenQueries(
ASTs rewritten_queries; ASTs rewritten_queries;
/// Order is very important. We always execute alter first and then execute rename /// Order is very important. We always execute alter first and then execute rename
if (!rewritten_alter_query->command_list->commands.empty()) if (!rewritten_alter_query->command_list->children.empty())
rewritten_queries.push_back(rewritten_alter_query); rewritten_queries.push_back(rewritten_alter_query);
if (!rewritten_rename_query->elements.empty()) if (!rewritten_rename_query->elements.empty())

View File

@ -29,7 +29,7 @@ static bool tryExtractConstValueFromCondition(const ASTPtr & condition, bool & v
/// cast of numeric constant in condition to UInt8 /// cast of numeric constant in condition to UInt8
if (const auto * function = condition->as<ASTFunction>()) if (const auto * function = condition->as<ASTFunction>())
{ {
if (function->name == "CAST") if (function->name == "cast")
{ {
if (const auto * expr_list = function->arguments->as<ASTExpressionList>()) if (const auto * expr_list = function->arguments->as<ASTExpressionList>())
{ {
@ -64,13 +64,17 @@ void OptimizeIfWithConstantConditionVisitor::visit(ASTPtr & current_ast)
continue; continue;
} }
if (!function_node->arguments)
throw Exception("Wrong number of arguments for function 'if' (0 instead of 3)", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
if (function_node->arguments->children.size() != 3)
throw Exception(
"Wrong number of arguments for function 'if' (" + toString(function_node->arguments->children.size()) + " instead of 3)",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
visit(function_node->arguments); visit(function_node->arguments);
const auto * args = function_node->arguments->as<ASTExpressionList>(); const auto * args = function_node->arguments->as<ASTExpressionList>();
if (args->children.size() != 3)
throw Exception("Wrong number of arguments for function 'if' (" + toString(args->children.size()) + " instead of 3)",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
ASTPtr condition_expr = args->children[0]; ASTPtr condition_expr = args->children[0];
ASTPtr then_expr = args->children[1]; ASTPtr then_expr = args->children[1];
ASTPtr else_expr = args->children[2]; ASTPtr else_expr = args->children[2];

View File

@ -164,14 +164,17 @@ void QueryNormalizer::visitChildren(const ASTPtr & node, Data & data)
if (func_node->name == "lambda") if (func_node->name == "lambda")
first_pos = 1; first_pos = 1;
auto & func_children = func_node->arguments->children; if (func_node->arguments)
for (size_t i = first_pos; i < func_children.size(); ++i)
{ {
auto & child = func_children[i]; auto & func_children = func_node->arguments->children;
if (needVisitChild(child)) for (size_t i = first_pos; i < func_children.size(); ++i)
visit(child, data); {
auto & child = func_children[i];
if (needVisitChild(child))
visit(child, data);
}
} }
} }
else if (!node->as<ASTSelectQuery>()) else if (!node->as<ASTSelectQuery>())

View File

@ -22,7 +22,7 @@ static bool removeInjectiveFunction(ASTPtr & ast, const Context & context, const
if (!func) if (!func)
return false; return false;
if (func->arguments->children.size() != 1) if (!func->arguments || func->arguments->children.size() != 1)
return false; return false;
if (!function_factory.get(func->name, context)->isInjective({})) if (!function_factory.get(func->name, context)->isInjective({}))

View File

@ -62,7 +62,7 @@ void RewriteAnyFunctionMatcher::visit(ASTPtr & ast, Data & data)
void RewriteAnyFunctionMatcher::visit(const ASTFunction & func, ASTPtr & ast, Data & data) void RewriteAnyFunctionMatcher::visit(const ASTFunction & func, ASTPtr & ast, Data & data)
{ {
if (func.arguments->children.empty() || !func.arguments->children[0]) if (!func.arguments || func.arguments->children.empty() || !func.arguments->children[0])
return; return;
if (func.name != "any" && func.name != "anyLast") if (func.name != "any" && func.name != "anyLast")

View File

@ -28,6 +28,7 @@ class ASTQueryWithTableAndOutput;
class ASTIdentifier; class ASTIdentifier;
class Context; class Context;
// TODO(ilezhankin): refactor and merge |ASTTableIdentifier|
struct StorageID struct StorageID
{ {
String database_name; String database_name;

View File

@ -126,6 +126,8 @@ void TranslateQualifiedNamesMatcher::visit(ASTFunction & node, const ASTPtr &, D
{ {
ASTPtr & func_arguments = node.arguments; ASTPtr & func_arguments = node.arguments;
if (!func_arguments) return;
String func_name_lowercase = Poco::toLower(node.name); String func_name_lowercase = Poco::toLower(node.name);
if (func_name_lowercase == "count" && if (func_name_lowercase == "count" &&
func_arguments->children.size() == 1 && func_arguments->children.size() == 1 &&

View File

@ -380,8 +380,9 @@ std::vector<const ASTFunction *> getAggregates(ASTPtr & query, const ASTSelectQu
/// There can not be other aggregate functions within the aggregate functions. /// There can not be other aggregate functions within the aggregate functions.
for (const ASTFunction * node : data.aggregates) for (const ASTFunction * node : data.aggregates)
for (auto & arg : node->arguments->children) if (node->arguments)
assertNoAggregates(arg, "inside another aggregate function"); for (auto & arg : node->arguments->children)
assertNoAggregates(arg, "inside another aggregate function");
return data.aggregates; return data.aggregates;
} }

View File

@ -11,7 +11,7 @@ namespace DB
ASTPtr addTypeConversionToAST(ASTPtr && ast, const String & type_name) ASTPtr addTypeConversionToAST(ASTPtr && ast, const String & type_name)
{ {
auto func = makeASTFunction("CAST", ast, std::make_shared<ASTLiteral>(type_name)); auto func = makeASTFunction("cast", ast, std::make_shared<ASTLiteral>(type_name));
if (ASTWithAlias * ast_with_alias = dynamic_cast<ASTWithAlias *>(ast.get())) if (ASTWithAlias * ast_with_alias = dynamic_cast<ASTWithAlias *>(ast.get()))
{ {

View File

@ -15,18 +15,23 @@
#include <DataStreams/InputStreamFromASTInsertQuery.h> #include <DataStreams/InputStreamFromASTInsertQuery.h>
#include <DataStreams/CountingBlockOutputStream.h> #include <DataStreams/CountingBlockOutputStream.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTInsertQuery.h> #include <Parsers/ASTInsertQuery.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTSelectQuery.h> #include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTShowProcesslistQuery.h> #include <Parsers/ASTShowProcesslistQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ParserQuery.h>
#include <Parsers/parseQuery.h>
#include <Parsers/queryToString.h>
#include <Parsers/ASTWatchQuery.h> #include <Parsers/ASTWatchQuery.h>
#include <Parsers/Lexer.h> #include <Parsers/Lexer.h>
#if !defined(ARCADIA_BUILD)
# include <Parsers/New/parseQuery.h> // Y_IGNORE
#endif
#include <Parsers/parseQuery.h>
#include <Parsers/ParserQuery.h>
#include <Parsers/queryToString.h>
#include <Storages/StorageInput.h> #include <Storages/StorageInput.h>
#include <Access/EnabledQuota.h> #include <Access/EnabledQuota.h>
@ -147,10 +152,11 @@ static void logQuery(const String & query, const Context & context, bool interna
const auto & initial_query_id = client_info.initial_query_id; const auto & initial_query_id = client_info.initial_query_id;
const auto & current_user = client_info.current_user; const auto & current_user = client_info.current_user;
LOG_DEBUG(&Poco::Logger::get("executeQuery"), "(from {}{}{}) {}", LOG_DEBUG(&Poco::Logger::get("executeQuery"), "(from {}{}{}, using {} parser) {}",
client_info.current_address.toString(), client_info.current_address.toString(),
(current_user != "default" ? ", user: " + current_user : ""), (current_user != "default" ? ", user: " + current_user : ""),
(!initial_query_id.empty() && current_query_id != initial_query_id ? ", initial_query_id: " + initial_query_id : std::string()), (!initial_query_id.empty() && current_query_id != initial_query_id ? ", initial_query_id: " + initial_query_id : std::string()),
(context.getSettingsRef().use_antlr_parser ? "new" : "old"),
joinLines(query)); joinLines(query));
if (client_info.client_trace_context.trace_id) if (client_info.client_trace_context.trace_id)
@ -321,19 +327,33 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
const Settings & settings = context.getSettingsRef(); const Settings & settings = context.getSettingsRef();
ParserQuery parser(end);
ASTPtr ast; ASTPtr ast;
const char * query_end; const char * query_end;
/// Don't limit the size of internal queries. /// Don't limit the size of internal queries.
size_t max_query_size = 0; size_t max_query_size = 0;
if (!internal) if (!internal) max_query_size = settings.max_query_size;
max_query_size = settings.max_query_size;
try try
{ {
/// TODO Parser should fail early when max_query_size limit is reached. #if !defined(ARCADIA_BUILD)
if (settings.use_antlr_parser)
{
ast = parseQuery(begin, end, max_query_size, settings.max_parser_depth);
}
else
{
ParserQuery parser(end);
/// TODO: parser should fail early when max_query_size limit is reached.
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
}
#else
ParserQuery parser(end);
/// TODO: parser should fail early when max_query_size limit is reached.
ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth); ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth);
#endif
/// Interpret SETTINGS clauses as early as possible (before invoking the corresponding interpreter), /// Interpret SETTINGS clauses as early as possible (before invoking the corresponding interpreter),
/// to allow settings to take effect. /// to allow settings to take effect.
@ -874,7 +894,7 @@ void executeQuery(
end = istr.buffer().end(); end = istr.buffer().end();
istr.position() += end - begin; istr.position() += end - begin;
/// Actually we don't know will query has additional data or not. /// Actually we don't know will query has additional data or not.
/// But we can't check istr.eof(), because begin and end pointers will became invalid /// But we can't check istr.eof(), because begin and end pointers will become invalid
may_have_tail = true; may_have_tail = true;
} }
else else

View File

@ -43,7 +43,7 @@ void addDefaultRequiredExpressionsRecursively(Block & block, const String & requ
RequiredSourceColumnsVisitor(columns_context).visit(column_default_expr); RequiredSourceColumnsVisitor(columns_context).visit(column_default_expr);
NameSet required_columns_names = columns_context.requiredColumns(); NameSet required_columns_names = columns_context.requiredColumns();
auto cast_func = makeASTFunction("CAST", column_default_expr, std::make_shared<ASTLiteral>(columns.get(required_column).type->getName())); auto cast_func = makeASTFunction("cast", column_default_expr, std::make_shared<ASTLiteral>(columns.get(required_column).type->getName()));
default_expr_list_accum->children.emplace_back(setAlias(cast_func, required_column)); default_expr_list_accum->children.emplace_back(setAlias(cast_func, required_column));
added_columns.emplace(required_column); added_columns.emplace(required_column);
@ -79,7 +79,7 @@ ASTPtr convertRequiredExpressions(Block & block, const NamesAndTypesList & requi
continue; continue;
auto cast_func = makeASTFunction( auto cast_func = makeASTFunction(
"CAST", std::make_shared<ASTIdentifier>(required_column.name), std::make_shared<ASTLiteral>(required_column.type->getName())); "cast", std::make_shared<ASTIdentifier>(required_column.name), std::make_shared<ASTLiteral>(required_column.type->getName()));
conversion_expr_list->children.emplace_back(setAlias(cast_func, required_column.name)); conversion_expr_list->children.emplace_back(setAlias(cast_func, required_column.name));

View File

@ -345,30 +345,6 @@ void ASTAlterCommand::formatImpl(
} }
ASTPtr ASTAlterCommandList::clone() const
{
auto res = std::make_shared<ASTAlterCommandList>();
for (ASTAlterCommand * command : commands)
res->add(command->clone());
return res;
}
void ASTAlterCommandList::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
for (size_t i = 0; i < commands.size(); ++i)
{
static_cast<IAST *>(commands[i])->formatImpl(settings, state, frame);
std::string comma = (i < (commands.size() - 1)) ? "," : "";
settings.ostr << (settings.hilite ? hilite_keyword : "") << comma << (settings.hilite ? hilite_none : "");
settings.ostr << settings.nl_or_ws;
}
}
/** Get the text that identifies this element. */ /** Get the text that identifies this element. */
String ASTAlterQuery::getID(char delim) const String ASTAlterQuery::getID(char delim) const
{ {

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <Parsers/IAST.h> #include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTQueryWithTableAndOutput.h>
#include <Parsers/ASTQueryWithOnCluster.h> #include <Parsers/ASTQueryWithOnCluster.h>
#include <Parsers/ASTQueryWithTableAndOutput.h>
#include <Parsers/ASTTTLElement.h> #include <Parsers/ASTTTLElement.h>
#include <Parsers/IAST.h>
namespace DB namespace DB
@ -179,31 +180,12 @@ protected:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
}; };
class ASTAlterCommandList : public IAST
{
public:
std::vector<ASTAlterCommand *> commands;
void add(const ASTPtr & command)
{
commands.push_back(command->as<ASTAlterCommand>());
children.push_back(command);
}
String getID(char) const override { return "AlterCommandList"; }
ASTPtr clone() const override;
protected:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
};
class ASTAlterQuery : public ASTQueryWithTableAndOutput, public ASTQueryWithOnCluster class ASTAlterQuery : public ASTQueryWithTableAndOutput, public ASTQueryWithOnCluster
{ {
public: public:
bool is_live_view{false}; /// true for ALTER LIVE VIEW bool is_live_view{false}; /// true for ALTER LIVE VIEW
ASTAlterCommandList * command_list = nullptr; ASTExpressionList * command_list = nullptr;
String getID(char) const override; String getID(char) const override;

View File

@ -4,10 +4,10 @@
#include <Parsers/ASTQueryWithOnCluster.h> #include <Parsers/ASTQueryWithOnCluster.h>
#include <Parsers/ASTDictionary.h> #include <Parsers/ASTDictionary.h>
#include <Parsers/ASTDictionaryAttributeDeclaration.h> #include <Parsers/ASTDictionaryAttributeDeclaration.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTSelectWithUnionQuery.h> #include <Parsers/ASTSelectWithUnionQuery.h>
#include <Interpreters/StorageID.h> #include <Interpreters/StorageID.h>
namespace DB namespace DB
{ {

View File

@ -65,7 +65,7 @@ ASTPtr ASTDictionaryLayout::clone() const
{ {
auto res = std::make_shared<ASTDictionaryLayout>(); auto res = std::make_shared<ASTDictionaryLayout>();
res->layout_type = layout_type; res->layout_type = layout_type;
res->set(res->parameters, parameters->clone()); if (parameters) res->set(res->parameters, parameters->clone());
res->has_brackets = has_brackets; res->has_brackets = has_brackets;
return res; return res;
} }
@ -86,7 +86,7 @@ void ASTDictionaryLayout::formatImpl(const FormatSettings & settings,
if (has_brackets) if (has_brackets)
settings.ostr << "("; settings.ostr << "(";
parameters->formatImpl(settings, state, frame); if (parameters) parameters->formatImpl(settings, state, frame);
if (has_brackets) if (has_brackets)
settings.ostr << ")"; settings.ostr << ")";

View File

@ -29,12 +29,13 @@ void ASTFunction::appendColumnNameImpl(WriteBuffer & ostr) const
} }
writeChar('(', ostr); writeChar('(', ostr);
for (auto it = arguments->children.begin(); it != arguments->children.end(); ++it) if (arguments)
{ for (auto it = arguments->children.begin(); it != arguments->children.end(); ++it)
if (it != arguments->children.begin()) {
writeCString(", ", ostr); if (it != arguments->children.begin())
(*it)->appendColumnName(ostr); writeCString(", ", ostr);
} (*it)->appendColumnName(ostr);
}
writeChar(')', ostr); writeChar(')', ostr);
} }
@ -64,6 +65,35 @@ void ASTFunction::updateTreeHashImpl(SipHash & hash_state) const
} }
ASTPtr ASTFunction::toLiteral() const
{
if (!arguments) return {};
if (name == "array")
{
Array array;
for (const auto & arg : arguments->children)
{
if (auto * literal = arg->as<ASTLiteral>())
array.push_back(literal->value);
else if (auto * func = arg->as<ASTFunction>())
{
if (auto func_literal = func->toLiteral())
array.push_back(func_literal->as<ASTLiteral>()->value);
}
else
/// Some of the Array arguments is not literal
return {};
}
return std::make_shared<ASTLiteral>(array);
}
return {};
}
/** A special hack. If it's [I]LIKE or NOT [I]LIKE expression and the right hand side is a string literal, /** A special hack. If it's [I]LIKE or NOT [I]LIKE expression and the right hand side is a string literal,
* we will highlight unescaped metacharacters % and _ in string literal for convenience. * we will highlight unescaped metacharacters % and _ in string literal for convenience.
* Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes. * Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes.
@ -378,12 +408,14 @@ void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, Format
settings.ostr << (settings.hilite ? hilite_function : "") << ')'; settings.ostr << (settings.hilite ? hilite_function : "") << ')';
} }
if (arguments) if ((arguments && !arguments->children.empty()) || !no_empty_args)
{
settings.ostr << '(' << (settings.hilite ? hilite_none : ""); settings.ostr << '(' << (settings.hilite ? hilite_none : "");
if (arguments)
{
bool special_hilite_regexp = settings.hilite bool special_hilite_regexp = settings.hilite
&& (name == "match" || name == "extract" || name == "extractAll" || name == "replaceRegexpOne" || name == "replaceRegexpAll"); && (name == "match" || name == "extract" || name == "extractAll" || name == "replaceRegexpOne"
|| name == "replaceRegexpAll");
for (size_t i = 0, size = arguments->children.size(); i < size; ++i) for (size_t i = 0, size = arguments->children.size(); i < size; ++i)
{ {
@ -397,10 +429,11 @@ void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, Format
if (!special_hilite) if (!special_hilite)
arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens); arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens);
} }
settings.ostr << (settings.hilite ? hilite_function : "") << ')';
} }
if ((arguments && !arguments->children.empty()) || !no_empty_args)
settings.ostr << (settings.hilite ? hilite_function : "") << ')';
settings.ostr << (settings.hilite ? hilite_none : ""); settings.ostr << (settings.hilite ? hilite_none : "");
} }
} }

View File

@ -18,7 +18,9 @@ public:
/// parameters - for parametric aggregate function. Example: quantile(0.9)(x) - what in first parens are 'parameters'. /// parameters - for parametric aggregate function. Example: quantile(0.9)(x) - what in first parens are 'parameters'.
ASTPtr parameters; ASTPtr parameters;
public: /// do not print empty parentheses if there are no args - compatibility with new AST for data types and engine names.
bool no_empty_args = false;
/** Get text identifying the AST node. */ /** Get text identifying the AST node. */
String getID(char delim) const override; String getID(char delim) const override;
@ -28,6 +30,8 @@ public:
ASTSelectWithUnionQuery * tryGetQueryArgument() const; ASTSelectWithUnionQuery * tryGetQueryArgument() const;
ASTPtr toLiteral() const; // Try to convert functions like Array or Tuple to a literal form.
protected: protected:
void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
void appendColumnNameImpl(WriteBuffer & ostr) const override; void appendColumnNameImpl(WriteBuffer & ostr) const override;

View File

@ -73,7 +73,6 @@ private:
void resetFullName(); void resetFullName();
}; };
/// ASTIdentifier Helpers: hide casts and semantic. /// ASTIdentifier Helpers: hide casts and semantic.
ASTPtr createTableIdentifier(const String & database_name, const String & table_name); ASTPtr createTableIdentifier(const String & database_name, const String & table_name);

View File

@ -1,20 +1,23 @@
#pragma once #pragma once
#include <Core/Field.h> #include <Core/Field.h>
#include <Common/FieldVisitors.h>
#include <Parsers/ASTWithAlias.h> #include <Parsers/ASTWithAlias.h>
#include <Parsers/TokenIterator.h> #include <Parsers/TokenIterator.h>
#include <Common/FieldVisitors.h>
#include <optional> #include <optional>
namespace DB namespace DB
{ {
/** Literal (atomic) - number, string, NULL /// Literal (atomic) - number, string, NULL
*/
class ASTLiteral : public ASTWithAlias class ASTLiteral : public ASTWithAlias
{ {
public: public:
explicit ASTLiteral(Field && value_) : value(value_) {}
explicit ASTLiteral(const Field & value_) : value(value_) {}
Field value; Field value;
/// For ConstantExpressionTemplate /// For ConstantExpressionTemplate
@ -30,11 +33,6 @@ public:
*/ */
String unique_column_name; String unique_column_name;
public:
ASTLiteral(Field && value_) : value(value_) {}
ASTLiteral(const Field & value_) : value(value_) {}
/** Get the text that identifies this element. */ /** Get the text that identifies this element. */
String getID(char delim) const override { return "Literal" + (delim + applyVisitor(FieldVisitorDump(), value)); } String getID(char delim) const override { return "Literal" + (delim + applyVisitor(FieldVisitorDump(), value)); }

View File

@ -23,20 +23,6 @@ public:
ASTPtr fill_to; ASTPtr fill_to;
ASTPtr fill_step; ASTPtr fill_step;
ASTOrderByElement(
const int direction_, const int nulls_direction_, const bool nulls_direction_was_explicitly_specified_,
ASTPtr & collation_, const bool with_fill_, ASTPtr & fill_from_, ASTPtr & fill_to_, ASTPtr & fill_step_)
: direction(direction_)
, nulls_direction(nulls_direction_)
, nulls_direction_was_explicitly_specified(nulls_direction_was_explicitly_specified_)
, collation(collation_)
, with_fill(with_fill_)
, fill_from(fill_from_)
, fill_to(fill_to_)
, fill_step(fill_step_)
{
}
String getID(char) const override { return "OrderByElement"; } String getID(char) const override { return "OrderByElement"; }
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -26,7 +26,7 @@ public:
Rational ratio; Rational ratio;
ASTSampleRatio(Rational & ratio_) : ratio(ratio_) {} explicit ASTSampleRatio(const Rational & ratio_) : ratio(ratio_) {}
String getID(char delim) const override { return "SampleRatio" + (delim + toString(ratio)); } String getID(char delim) const override { return "SampleRatio" + (delim + toString(ratio)); }

View File

@ -30,7 +30,7 @@ namespace DB
* , (comma) * , (comma)
* *
* In all kinds except cross and comma, there are join condition in one of following forms: * In all kinds except cross and comma, there are join condition in one of following forms:
* USING (a, b c) * USING (a, b, c)
* USING a, b, c * USING a, b, c
* ON expr... * ON expr...
* *

View File

@ -441,7 +441,7 @@ bool ParserCastExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expect
expr_list_args->children.push_back(std::move(type_literal)); expr_list_args->children.push_back(std::move(type_literal));
auto func_node = std::make_shared<ASTFunction>(); auto func_node = std::make_shared<ASTFunction>();
func_node->name = "CAST"; func_node->name = "cast";
func_node->arguments = std::move(expr_list_args); func_node->arguments = std::move(expr_list_args);
func_node->children.push_back(func_node->arguments); func_node->children.push_back(func_node->arguments);
@ -1705,12 +1705,21 @@ bool ParserOrderByElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expect
return false; return false;
} }
node = std::make_shared<ASTOrderByElement>( auto elem = std::make_shared<ASTOrderByElement>();
direction, nulls_direction, nulls_direction_was_explicitly_specified, locale_node,
has_with_fill, fill_from, fill_to, fill_step); elem->direction = direction;
node->children.push_back(expr_elem); elem->nulls_direction = nulls_direction;
elem->nulls_direction_was_explicitly_specified = nulls_direction_was_explicitly_specified;
elem->collation = locale_node;
elem->with_fill = has_with_fill;
elem->fill_from = fill_from;
elem->fill_to = fill_to;
elem->fill_step = fill_step;
elem->children.push_back(expr_elem);
if (locale_node) if (locale_node)
node->children.push_back(locale_node); elem->children.push_back(locale_node);
node = elem;
return true; return true;
} }
@ -1887,13 +1896,18 @@ bool ParserIdentifierWithOptionalParameters::parseImpl(Pos & pos, ASTPtr & node,
ParserIdentifierWithParameters parametric; ParserIdentifierWithParameters parametric;
if (parametric.parse(pos, node, expected)) if (parametric.parse(pos, node, expected))
{
auto * func = node->as<ASTFunction>();
func->no_empty_args = true;
return true; return true;
}
ASTPtr ident; ASTPtr ident;
if (non_parametric.parse(pos, ident, expected)) if (non_parametric.parse(pos, ident, expected))
{ {
auto func = std::make_shared<ASTFunction>(); auto func = std::make_shared<ASTFunction>();
tryGetIdentifierNameInto(ident, func->name); tryGetIdentifierNameInto(ident, func->name);
func->no_empty_args = true;
node = func; node = func;
return true; return true;
} }

View File

@ -13,6 +13,7 @@ namespace ErrorCodes
extern const int TOO_BIG_AST; extern const int TOO_BIG_AST;
extern const int TOO_DEEP_AST; extern const int TOO_DEEP_AST;
extern const int BAD_ARGUMENTS; extern const int BAD_ARGUMENTS;
extern const int UNKNOWN_ELEMENT_IN_AST;
} }
@ -154,7 +155,10 @@ void IAST::dumpTree(WriteBuffer & ostr, size_t indent) const
writePointerHex(this, ostr); writePointerHex(this, ostr);
writeChar('\n', ostr); writeChar('\n', ostr);
for (const auto & child : children) for (const auto & child : children)
{
if (!child) throw Exception("Can't dump nullptr child", ErrorCodes::UNKNOWN_ELEMENT_IN_AST);
child->dumpTree(ostr, indent + 1); child->dumpTree(ostr, indent + 1);
}
} }
} }

View File

@ -0,0 +1,687 @@
#include <Parsers/New/AST/AlterTableQuery.h>
#include <Interpreters/StorageID.h>
#include <Parsers/ASTAlterQuery.h>
#include <Parsers/ASTAssignment.h>
#include <Parsers/ASTColumnDeclaration.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTPartition.h>
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/AST/TableElementExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
AssignmentExpr::AssignmentExpr(PtrTo<Identifier> identifier, PtrTo<ColumnExpr> expr) : INode{identifier, expr}
{
}
ASTPtr AssignmentExpr::convertToOld() const
{
auto expr = std::make_shared<ASTAssignment>();
expr->column_name = get(IDENTIFIER)->convertToOld()->getColumnName();
expr->children.push_back(get(EXPR)->convertToOld());
return expr;
}
PartitionClause::PartitionClause(PtrTo<Literal> id) : PartitionClause(ClauseType::ID, {id})
{
}
PartitionClause::PartitionClause(PtrTo<List<Literal>> list) : PartitionClause(ClauseType::LIST, {list})
{
}
PartitionClause::PartitionClause(ClauseType type, PtrList exprs) : INode(exprs), clause_type(type)
{
}
ASTPtr PartitionClause::convertToOld() const
{
auto partition = std::make_shared<ASTPartition>();
switch(clause_type)
{
case ClauseType::ID:
partition->id = get<StringLiteral>(ID)->as<String>();
break;
case ClauseType::LIST:
{
auto tuple = std::make_shared<ASTFunction>();
tuple->name = "tuple";
tuple->arguments = std::make_shared<ASTExpressionList>();
for (const auto & child : get(LIST)->as<List<Literal> &>())
tuple->arguments->children.push_back(child->convertToOld());
tuple->children.push_back(tuple->arguments);
partition->value = tuple;
partition->children.push_back(partition->value);
partition->fields_count = get<List<Literal>>(LIST)->size();
partition->fields_str = get(LIST)->toString();
}
break;
}
return partition;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createAddColumn(bool if_not_exists, PtrTo<TableElementExpr> element, PtrTo<Identifier> after)
{
assert(element->getType() == TableElementExpr::ExprType::COLUMN);
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::ADD_COLUMN, {element, after}));
query->if_not_exists = if_not_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createAddIndex(bool if_not_exists, PtrTo<TableElementExpr> element, PtrTo<Identifier> after)
{
assert(element->getType() == TableElementExpr::ExprType::INDEX);
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::ADD_INDEX, {element, after}));
query->if_not_exists = if_not_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createAttach(PtrTo<PartitionClause> clause, PtrTo<TableIdentifier> from)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::ATTACH, {clause, from}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createClear(bool if_exists, PtrTo<Identifier> identifier, PtrTo<PartitionClause> in)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::CLEAR, {identifier, in}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createCodec(bool if_exists, PtrTo<Identifier> identifier, PtrTo<CodecExpr> codec)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::CODEC, {identifier, codec}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createComment(bool if_exists, PtrTo<Identifier> identifier, PtrTo<StringLiteral> comment)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::COMMENT, {identifier, comment}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createDelete(PtrTo<ColumnExpr> expr)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::DELETE, {expr}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createDetach(PtrTo<PartitionClause> clause)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::DETACH, {clause}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createDropColumn(bool if_exists, PtrTo<Identifier> identifier)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::DROP_COLUMN, {identifier}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createDropIndex(bool if_exists, PtrTo<Identifier> identifier)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::DROP_INDEX, {identifier}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createDropPartition(PtrTo<PartitionClause> clause)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::DROP_PARTITION, {clause}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createFreezePartition(PtrTo<PartitionClause> clause)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::FREEZE_PARTITION, {clause}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createModify(bool if_exists, PtrTo<TableElementExpr> element)
{
// TODO: assert(element->getType() == TableElementExpr::ExprType::COLUMN);
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::MODIFY, {element}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createMovePartitionToDisk(PtrTo<PartitionClause> clause, PtrTo<StringLiteral> literal)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::MOVE_PARTITION_TO_DISK, {clause, literal}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createMovePartitionToTable(PtrTo<PartitionClause> clause, PtrTo<TableIdentifier> identifier)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::MOVE_PARTITION_TO_TABLE, {clause, identifier}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createMovePartitionToVolume(PtrTo<PartitionClause> clause, PtrTo<StringLiteral> literal)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::MOVE_PARTITION_TO_VOLUME, {clause, literal}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createOrderBy(PtrTo<ColumnExpr> expr)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::ORDER_BY, {expr}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createRemove(bool if_exists, PtrTo<Identifier> identifier, TableColumnPropertyType type)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::REMOVE, {identifier}));
query->if_exists = if_exists;
query->property_type = type;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createRemoveTTL()
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::REMOVE_TTL, {}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createRename(bool if_exists, PtrTo<Identifier> identifier, PtrTo<Identifier> to)
{
PtrTo<AlterTableClause> query(new AlterTableClause(ClauseType::RENAME, {identifier, to}));
query->if_exists = if_exists;
return query;
}
// static
PtrTo<AlterTableClause> AlterTableClause::createReplace(PtrTo<PartitionClause> clause, PtrTo<TableIdentifier> from)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::REPLACE, {clause, from}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createTTL(PtrTo<TTLClause> clause)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::TTL, {clause}));
}
// static
PtrTo<AlterTableClause> AlterTableClause::createUpdate(PtrTo<AssignmentExprList> list, PtrTo<WhereClause> where)
{
return PtrTo<AlterTableClause>(new AlterTableClause(ClauseType::UPDATE, {list, where}));
}
ASTPtr AlterTableClause::convertToOld() const
{
auto command = std::make_shared<ASTAlterCommand>();
switch(clause_type)
{
case ClauseType::ADD_COLUMN:
command->type = ASTAlterCommand::ADD_COLUMN;
command->if_not_exists = if_not_exists;
// TODO: command->first
command->col_decl = get(ELEMENT)->convertToOld();
if (has(AFTER)) command->column = get(AFTER)->convertToOld();
break;
case ClauseType::ADD_INDEX:
command->type = ASTAlterCommand::ADD_INDEX;
command->if_not_exists = if_not_exists;
command->index_decl = get(ELEMENT)->convertToOld();
if (has(AFTER)) command->index = get(AFTER)->convertToOld();
break;
case ClauseType::ATTACH:
command->type = ASTAlterCommand::ATTACH_PARTITION;
command->partition = get(PARTITION)->convertToOld();
if (has(FROM))
{
auto table_id = getTableIdentifier(get(FROM)->convertToOld());
command->from_database = table_id.database_name;
command->from_table = table_id.table_name;
command->replace = false;
command->type = ASTAlterCommand::REPLACE_PARTITION;
}
break;
case ClauseType::CLEAR:
command->type = ASTAlterCommand::DROP_COLUMN;
command->if_exists = if_exists;
command->clear_column = true;
command->detach = false;
command->column = get(COLUMN)->convertToOld();
if (has(IN)) command->partition = get(IN)->convertToOld();
break;
case ClauseType::CODEC:
command->type = ASTAlterCommand::MODIFY_COLUMN;
command->if_exists = if_exists;
{
auto column = std::make_shared<ASTColumnDeclaration>();
column->name = get(COLUMN)->toString();
column->codec = get(CODEC)->convertToOld();
command->col_decl = column;
}
break;
case ClauseType::COMMENT:
command->type = ASTAlterCommand::COMMENT_COLUMN;
command->if_exists = if_exists;
command->column = get(COLUMN)->convertToOld();
command->comment = get(COMMENT)->convertToOld();
break;
case ClauseType::DELETE:
command->type = ASTAlterCommand::DELETE;
command->predicate = get(EXPR)->convertToOld();
break;
case ClauseType::DETACH:
command->type = ASTAlterCommand::DROP_PARTITION;
command->detach = true;
command->partition = get(PARTITION)->convertToOld();
break;
case ClauseType::DROP_COLUMN:
command->type = ASTAlterCommand::DROP_COLUMN;
command->if_exists = if_exists;
command->detach = false;
command->column = get(COLUMN)->convertToOld();
break;
case ClauseType::DROP_INDEX:
command->type = ASTAlterCommand::DROP_INDEX;
command->if_exists = if_exists;
command->detach = false;
command->index = get(COLUMN)->convertToOld();
break;
case ClauseType::DROP_PARTITION:
command->type = ASTAlterCommand::DROP_PARTITION;
command->partition = get(PARTITION)->convertToOld();
break;
case ClauseType::FREEZE_PARTITION:
if (has(PARTITION))
{
command->type = ASTAlterCommand::FREEZE_PARTITION;
command->partition = get(PARTITION)->convertToOld();
}
else
command->type = ASTAlterCommand::FREEZE_ALL;
break;
case ClauseType::MODIFY:
command->type = ASTAlterCommand::MODIFY_COLUMN;
command->if_exists = if_exists;
command->col_decl = get(ELEMENT)->convertToOld();
break;
case ClauseType::MOVE_PARTITION_TO_DISK:
command->type = ASTAlterCommand::MOVE_PARTITION;
command->partition = get(PARTITION)->convertToOld();
command->move_destination_type = DataDestinationType::DISK;
command->move_destination_name = get(TO)->convertToOld()->as<ASTLiteral>()->value.get<String>();
break;
case ClauseType::MOVE_PARTITION_TO_TABLE:
command->type = ASTAlterCommand::MOVE_PARTITION;
command->partition = get(PARTITION)->convertToOld();
command->move_destination_type = DataDestinationType::TABLE;
{
auto table_id = getTableIdentifier(get(TO)->convertToOld());
command->to_database = table_id.database_name;
command->to_table = table_id.table_name;
}
break;
case ClauseType::MOVE_PARTITION_TO_VOLUME:
command->type = ASTAlterCommand::MOVE_PARTITION;
command->partition = get(PARTITION)->convertToOld();
command->move_destination_type = DataDestinationType::VOLUME;
command->move_destination_name = get(TO)->convertToOld()->as<ASTLiteral>()->value.get<String>();
break;
case ClauseType::REMOVE:
command->type = ASTAlterCommand::MODIFY_COLUMN;
command->if_exists = if_exists;
{
auto col_decl = std::make_shared<ASTColumnDeclaration>();
col_decl->name = get(ELEMENT)->convertToOld()->getColumnName();
command->col_decl = col_decl;
}
switch(property_type)
{
case TableColumnPropertyType::ALIAS:
command->remove_property = "ALIAS";
break;
case TableColumnPropertyType::CODEC:
command->remove_property = "CODEC";
break;
case TableColumnPropertyType::COMMENT:
command->remove_property = "COMMENT";
break;
case TableColumnPropertyType::DEFAULT:
command->remove_property = "DEFAULT";
break;
case TableColumnPropertyType::MATERIALIZED:
command->remove_property = "MATERIALIZED";
break;
case TableColumnPropertyType::TTL:
command->remove_property = "TTL";
break;
}
break;
case ClauseType::REMOVE_TTL:
command->type = ASTAlterCommand::REMOVE_TTL;
break;
case ClauseType::RENAME:
command->type = ASTAlterCommand::RENAME_COLUMN;
command->column = get(COLUMN)->convertToOld();
command->rename_to = get(TO)->convertToOld();
break;
case ClauseType::ORDER_BY:
command->type = ASTAlterCommand::MODIFY_ORDER_BY;
command->order_by = get(EXPR)->convertToOld();
break;
case ClauseType::REPLACE:
command->type = ASTAlterCommand::REPLACE_PARTITION;
command->replace = true;
command->partition = get(PARTITION)->convertToOld();
{
auto table_id = getTableIdentifier(get(FROM)->convertToOld());
command->from_database = table_id.database_name;
command->from_table = table_id.table_name;
}
break;
case ClauseType::TTL:
command->type = ASTAlterCommand::MODIFY_TTL;
command->ttl = get(CLAUSE)->convertToOld();
break;
case ClauseType::UPDATE:
command->type = ASTAlterCommand::UPDATE;
command->update_assignments = get(ASSIGNMENTS)->convertToOld();
command->predicate = get(WHERE)->convertToOld();
break;
}
if (command->col_decl)
command->children.push_back(command->col_decl);
if (command->column)
command->children.push_back(command->column);
if (command->partition)
command->children.push_back(command->partition);
if (command->order_by)
command->children.push_back(command->order_by);
if (command->sample_by)
command->children.push_back(command->sample_by);
if (command->predicate)
command->children.push_back(command->predicate);
if (command->update_assignments)
command->children.push_back(command->update_assignments);
if (command->values)
command->children.push_back(command->values);
if (command->comment)
command->children.push_back(command->comment);
if (command->ttl)
command->children.push_back(command->ttl);
if (command->settings_changes)
command->children.push_back(command->settings_changes);
return command;
}
AlterTableClause::AlterTableClause(ClauseType type, PtrList exprs) : INode(exprs), clause_type(type)
{
}
AlterTableQuery::AlterTableQuery(PtrTo<ClusterClause> cluster, PtrTo<TableIdentifier> identifier, PtrTo<List<AlterTableClause>> clauses)
: DDLQuery(cluster, {identifier, clauses})
{
}
ASTPtr AlterTableQuery::convertToOld() const
{
auto query = std::make_shared<ASTAlterQuery>();
{
auto table_id = getTableIdentifier(get(TABLE)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
}
query->cluster = cluster_name;
query->set(query->command_list, get(CLAUSES)->convertToOld());
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseAddColumn(ClickHouseParser::AlterTableClauseAddColumnContext * ctx)
{
auto after = ctx->AFTER() ? visit(ctx->nestedIdentifier()).as<PtrTo<Identifier>>() : nullptr;
return AlterTableClause::createAddColumn(!!ctx->IF(), visit(ctx->tableColumnDfnt()), after);
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseAddIndex(ClickHouseParser::AlterTableClauseAddIndexContext * ctx)
{
auto after = ctx->AFTER() ? visit(ctx->nestedIdentifier()).as<PtrTo<Identifier>>() : nullptr;
return AlterTableClause::createAddIndex(!!ctx->IF(), visit(ctx->tableIndexDfnt()), after);
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseAttach(ClickHouseParser::AlterTableClauseAttachContext *ctx)
{
auto from = ctx->tableIdentifier() ? visit(ctx->tableIdentifier()).as<PtrTo<TableIdentifier>>() : nullptr;
return AlterTableClause::createAttach(visit(ctx->partitionClause()), from);
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseClear(ClickHouseParser::AlterTableClauseClearContext * ctx)
{
auto partition = ctx->partitionClause() ? visit(ctx->partitionClause()).as<PtrTo<PartitionClause>>() : nullptr;
return AlterTableClause::createClear(!!ctx->IF(), visit(ctx->nestedIdentifier()), partition);
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseComment(ClickHouseParser::AlterTableClauseCommentContext * ctx)
{
return AlterTableClause::createComment(!!ctx->IF(), visit(ctx->nestedIdentifier()), Literal::createString(ctx->STRING_LITERAL()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseDelete(ClickHouseParser::AlterTableClauseDeleteContext *ctx)
{
return AlterTableClause::createDelete(visit(ctx->columnExpr()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseDetach(ClickHouseParser::AlterTableClauseDetachContext *ctx)
{
return AlterTableClause::createDetach(visit(ctx->partitionClause()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseDropColumn(ClickHouseParser::AlterTableClauseDropColumnContext * ctx)
{
return AlterTableClause::createDropColumn(!!ctx->IF(), visit(ctx->nestedIdentifier()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseDropIndex(ClickHouseParser::AlterTableClauseDropIndexContext * ctx)
{
return AlterTableClause::createDropIndex(!!ctx->IF(), visit(ctx->nestedIdentifier()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseDropPartition(ClickHouseParser::AlterTableClauseDropPartitionContext *ctx)
{
return AlterTableClause::createDropPartition(visit(ctx->partitionClause()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseFreezePartition(ClickHouseParser::AlterTableClauseFreezePartitionContext *ctx)
{
auto clause = ctx->partitionClause() ? visit(ctx->partitionClause()).as<PtrTo<PartitionClause>>() : nullptr;
return AlterTableClause::createFreezePartition(clause);
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseModify(ClickHouseParser::AlterTableClauseModifyContext * ctx)
{
return AlterTableClause::createModify(!!ctx->IF(), visit(ctx->tableColumnDfnt()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseModifyCodec(ClickHouseParser::AlterTableClauseModifyCodecContext * ctx)
{
return AlterTableClause::createCodec(!!ctx->IF(), visit(ctx->nestedIdentifier()), visit(ctx->codecExpr()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseModifyComment(ClickHouseParser::AlterTableClauseModifyCommentContext *ctx)
{
return AlterTableClause::createComment(!!ctx->IF(), visit(ctx->nestedIdentifier()), Literal::createString(ctx->STRING_LITERAL()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseModifyOrderBy(ClickHouseParser::AlterTableClauseModifyOrderByContext * ctx)
{
return AlterTableClause::createOrderBy(visit(ctx->columnExpr()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseModifyRemove(ClickHouseParser::AlterTableClauseModifyRemoveContext *ctx)
{
return AlterTableClause::createRemove(!!ctx->IF(), visit(ctx->nestedIdentifier()), visit(ctx->tableColumnPropertyType()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseModifyTTL(ClickHouseParser::AlterTableClauseModifyTTLContext *ctx)
{
return AlterTableClause::createTTL(visit(ctx->ttlClause()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseMovePartition(ClickHouseParser::AlterTableClauseMovePartitionContext *ctx)
{
if (ctx->DISK())
return AlterTableClause::createMovePartitionToDisk(visit(ctx->partitionClause()), Literal::createString(ctx->STRING_LITERAL()));
if (ctx->TABLE())
return AlterTableClause::createMovePartitionToTable(visit(ctx->partitionClause()), visit(ctx->tableIdentifier()));
if (ctx->VOLUME())
return AlterTableClause::createMovePartitionToVolume(visit(ctx->partitionClause()), Literal::createString(ctx->STRING_LITERAL()));
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseRemoveTTL(ClickHouseParser::AlterTableClauseRemoveTTLContext *)
{
return AlterTableClause::createRemoveTTL();
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseRename(ClickHouseParser::AlterTableClauseRenameContext *ctx)
{
return AlterTableClause::createRename(!!ctx->IF(), visit(ctx->nestedIdentifier(0)), visit(ctx->nestedIdentifier(1)));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseReplace(ClickHouseParser::AlterTableClauseReplaceContext *ctx)
{
return AlterTableClause::createReplace(visit(ctx->partitionClause()), visit(ctx->tableIdentifier()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableClauseUpdate(ClickHouseParser::AlterTableClauseUpdateContext *ctx)
{
return AlterTableClause::createUpdate(visit(ctx->assignmentExprList()), visit(ctx->whereClause()));
}
antlrcpp::Any ParseTreeVisitor::visitAlterTableStmt(ClickHouseParser::AlterTableStmtContext * ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto list = std::make_shared<List<AlterTableClause>>();
for (auto * clause : ctx->alterTableClause()) list->push(visit(clause));
return std::make_shared<AlterTableQuery>(cluster, visit(ctx->tableIdentifier()), list);
}
antlrcpp::Any ParseTreeVisitor::visitAssignmentExpr(ClickHouseParser::AssignmentExprContext *ctx)
{
return std::make_shared<AssignmentExpr>(visit(ctx->nestedIdentifier()), visit(ctx->columnExpr()));
}
antlrcpp::Any ParseTreeVisitor::visitAssignmentExprList(ClickHouseParser::AssignmentExprListContext *ctx)
{
auto list = std::make_shared<AssignmentExprList>();
for (auto * expr : ctx->assignmentExpr()) list->push(visit(expr));
return list;
}
antlrcpp::Any ParseTreeVisitor::visitTableColumnPropertyType(ClickHouseParser::TableColumnPropertyTypeContext *ctx)
{
if (ctx->ALIAS()) return TableColumnPropertyType::ALIAS;
if (ctx->CODEC()) return TableColumnPropertyType::CODEC;
if (ctx->COMMENT()) return TableColumnPropertyType::COMMENT;
if (ctx->DEFAULT()) return TableColumnPropertyType::DEFAULT;
if (ctx->MATERIALIZED()) return TableColumnPropertyType::MATERIALIZED;
if (ctx->TTL()) return TableColumnPropertyType::TTL;
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitPartitionClause(ClickHouseParser::PartitionClauseContext *ctx)
{
if (ctx->STRING_LITERAL())
return std::make_shared<PartitionClause>(Literal::createString(ctx->STRING_LITERAL()));
auto expr = visit(ctx->columnExpr()).as<PtrTo<ColumnExpr>>();
if (expr->getType() == ColumnExpr::ExprType::LITERAL)
return std::make_shared<PartitionClause>(PtrTo<List<Literal>>(new List<Literal>{expr->getLiteral()}));
if (expr->getType() == ColumnExpr::ExprType::FUNCTION && expr->getFunctionName() == "tuple")
{
auto list = std::make_shared<List<Literal>>();
for (auto it = expr->argumentsBegin(); it != expr->argumentsEnd(); ++it)
{
auto * literal = (*it)->as<ColumnExpr>();
if (literal->getType() == ColumnExpr::ExprType::LITERAL)
list->push(literal->getLiteral());
else
{
// TODO: 'Expected tuple of literals as Partition Expression'.
}
}
return std::make_shared<PartitionClause>(list);
}
// TODO: 'Expected tuple of literals as Partition Expression'.
__builtin_unreachable();
}
}

View File

@ -0,0 +1,179 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class AssignmentExpr : public INode
{
public:
AssignmentExpr(PtrTo<Identifier> identifier, PtrTo<ColumnExpr> expr);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
IDENTIFIER = 0, // Identifier
EXPR = 1, // ColumnExpr
};
};
enum class TableColumnPropertyType
{
ALIAS,
CODEC,
COMMENT,
DEFAULT,
MATERIALIZED,
TTL,
};
class PartitionClause : public INode
{
public:
explicit PartitionClause(PtrTo<Literal> id);
explicit PartitionClause(PtrTo<List<Literal>> list);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
ID = 0, // Literal
LIST = 0, // List<Literal>
};
enum class ClauseType
{
ID,
LIST,
};
const ClauseType clause_type;
PartitionClause(ClauseType type, PtrList exprs);
};
class AlterTableClause : public INode
{
public:
static PtrTo<AlterTableClause> createAddColumn(bool if_not_exists, PtrTo<TableElementExpr> element, PtrTo<Identifier> after);
static PtrTo<AlterTableClause> createAddIndex(bool if_not_exists, PtrTo<TableElementExpr> element, PtrTo<Identifier> after);
static PtrTo<AlterTableClause> createAttach(PtrTo<PartitionClause> clause, PtrTo<TableIdentifier> from);
static PtrTo<AlterTableClause> createClear(bool if_exists, PtrTo<Identifier> identifier, PtrTo<PartitionClause> in);
static PtrTo<AlterTableClause> createCodec(bool if_exists, PtrTo<Identifier> identifier, PtrTo<CodecExpr> codec);
static PtrTo<AlterTableClause> createComment(bool if_exists, PtrTo<Identifier> identifier, PtrTo<StringLiteral> comment);
static PtrTo<AlterTableClause> createDelete(PtrTo<ColumnExpr> expr);
static PtrTo<AlterTableClause> createDetach(PtrTo<PartitionClause> clause);
static PtrTo<AlterTableClause> createDropColumn(bool if_exists, PtrTo<Identifier> identifier);
static PtrTo<AlterTableClause> createDropIndex(bool if_exists, PtrTo<Identifier> identifier);
static PtrTo<AlterTableClause> createDropPartition(PtrTo<PartitionClause> clause);
static PtrTo<AlterTableClause> createFreezePartition(PtrTo<PartitionClause> clause);
static PtrTo<AlterTableClause> createModify(bool if_exists, PtrTo<TableElementExpr> element);
static PtrTo<AlterTableClause> createMovePartitionToDisk(PtrTo<PartitionClause> clause, PtrTo<StringLiteral> literal);
static PtrTo<AlterTableClause> createMovePartitionToTable(PtrTo<PartitionClause> clause, PtrTo<TableIdentifier> identifier);
static PtrTo<AlterTableClause> createMovePartitionToVolume(PtrTo<PartitionClause> clause, PtrTo<StringLiteral> literal);
static PtrTo<AlterTableClause> createRemove(bool if_exists, PtrTo<Identifier> identifier, TableColumnPropertyType type);
static PtrTo<AlterTableClause> createRemoveTTL();
static PtrTo<AlterTableClause> createRename(bool if_exists, PtrTo<Identifier> identifier, PtrTo<Identifier> to);
static PtrTo<AlterTableClause> createOrderBy(PtrTo<ColumnExpr> expr);
static PtrTo<AlterTableClause> createReplace(PtrTo<PartitionClause> clause, PtrTo<TableIdentifier> from);
static PtrTo<AlterTableClause> createTTL(PtrTo<TTLClause> clause);
static PtrTo<AlterTableClause> createUpdate(PtrTo<AssignmentExprList> list, PtrTo<WhereClause> where);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
// ADD COLUMN or INDEX
ELEMENT = 0, // TableElementExpr
AFTER = 1, // Identifier (optional)
// ATTACH/REPLACE
PARTITION = 0, // PartitionClause
FROM = 1, // TableIdentifier (optional)
// CLEAR
COLUMN = 0, // Identifier
IN = 1, // PartitionClause
// CODEC
CODEC = 1, // CodecExpr
// COMMENT
COMMENT = 1, // StringLiteral
// DELETE
EXPR = 0, // ColumnExpr
// MOVE
// TO = 1, // TableIdentifier or StringLiteral
// RENAME
TO = 1, // Identifier
// TTL
CLAUSE = 0, // TTLClause
// UPDATE
ASSIGNMENTS = 0, // AssignmentExprList
WHERE = 1, // WhereClause
};
enum class ClauseType
{
ADD_COLUMN,
ADD_INDEX,
ATTACH,
CLEAR,
CODEC,
COMMENT,
DELETE,
DETACH,
DROP_COLUMN,
DROP_INDEX,
DROP_PARTITION,
FREEZE_PARTITION,
MODIFY,
MOVE_PARTITION_TO_DISK,
MOVE_PARTITION_TO_TABLE,
MOVE_PARTITION_TO_VOLUME,
ORDER_BY,
REMOVE,
REMOVE_TTL,
RENAME,
REPLACE,
TTL,
UPDATE,
};
const ClauseType clause_type;
TableColumnPropertyType property_type = TableColumnPropertyType::ALIAS; // default value to silence PVS-Studio
union
{
bool if_exists;
bool if_not_exists;
};
AlterTableClause(ClauseType type, PtrList exprs);
};
class AlterTableQuery : public DDLQuery
{
public:
AlterTableQuery(PtrTo<ClusterClause> cluster, PtrTo<TableIdentifier> identifier, PtrTo<List<AlterTableClause>> clauses);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
TABLE = 0, // TableIdentifier
CLAUSES = 1, // List<AlterTableClause>
};
};
}

View File

@ -0,0 +1,57 @@
#include <Parsers/New/AST/AttachQuery.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
// static
PtrTo<AttachQuery> AttachQuery::createDictionary(PtrTo<ClusterClause> clause, PtrTo<TableIdentifier> identifier)
{
return PtrTo<AttachQuery>(new AttachQuery(clause, QueryType::DICTIONARY, {identifier}));
}
AttachQuery::AttachQuery(PtrTo<ClusterClause> clause, QueryType type, PtrList exprs) : DDLQuery(clause, exprs), query_type(type)
{
}
ASTPtr AttachQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
query->attach = true;
switch(query_type)
{
case QueryType::DICTIONARY:
query->is_dictionary = true;
{
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
}
break;
}
query->cluster = cluster_name;
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitAttachDictionaryStmt(ClickHouseParser::AttachDictionaryStmtContext *ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
return AttachQuery::createDictionary(cluster, visit(ctx->tableIdentifier()));
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class AttachQuery : public DDLQuery
{
public:
static PtrTo<AttachQuery> createDictionary(PtrTo<ClusterClause> clause, PtrTo<TableIdentifier> identifier);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
};
enum class QueryType
{
DICTIONARY,
};
const QueryType query_type;
AttachQuery(PtrTo<ClusterClause> clause, QueryType type, PtrList exprs);
};
}

View File

@ -0,0 +1,44 @@
#include <Parsers/New/AST/CheckQuery.h>
#include <Interpreters/StorageID.h>
#include <Parsers/ASTCheckQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/New/AST/AlterTableQuery.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
CheckQuery::CheckQuery(PtrTo<TableIdentifier> identifier, PtrTo<PartitionClause> clause) : Query{identifier, clause}
{
}
ASTPtr CheckQuery::convertToOld() const
{
auto query = std::make_shared<ASTCheckQuery>();
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
if (has(PARTITION)) query->partition = get(PARTITION)->convertToOld();
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitCheckStmt(ClickHouseParser::CheckStmtContext *ctx)
{
auto partition = ctx->partitionClause() ? visit(ctx->partitionClause()).as<PtrTo<PartitionClause>>() : nullptr;
return std::make_shared<CheckQuery>(visit(ctx->tableIdentifier()), partition);
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <Parsers/New/AST/Query.h>
namespace DB::AST
{
class CheckQuery : public Query
{
public:
CheckQuery(PtrTo<TableIdentifier> identifier, PtrTo<PartitionClause> clause);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
PARTITION = 1, // PartitionClause (optional)
};
};
}

View File

@ -0,0 +1,588 @@
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/ASTAsterisk.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTQualifiedAsterisk.h>
#include <Parsers/ASTSubquery.h>
#include <Parsers/New/AST/ColumnTypeExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/ClickHouseLexer.h>
#include <Parsers/New/ClickHouseParser.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::ErrorCodes
{
extern int SYNTAX_ERROR;
}
namespace DB::AST
{
// static
PtrTo<ColumnExpr> ColumnExpr::createAlias(PtrTo<ColumnExpr> expr, PtrTo<Identifier> alias)
{
return PtrTo<ColumnExpr>(new ColumnExpr(ExprType::ALIAS, {expr, alias}));
}
// static
PtrTo<ColumnExpr> ColumnExpr::createAsterisk(PtrTo<TableIdentifier> identifier, bool single_column)
{
auto expr = PtrTo<ColumnExpr>(new ColumnExpr(ExprType::ASTERISK, {identifier}));
expr->expect_single_column = single_column;
return expr;
}
// static
PtrTo<ColumnExpr> ColumnExpr::createFunction(PtrTo<Identifier> name, PtrTo<ColumnParamList> params, PtrTo<ColumnExprList> args)
{
// FIXME: make sure that all function names are camel-case.
// Flatten some consequent binary operators to a single multi-operator, because they are left-associative.
if ((name->getName() == "or" || name->getName() == "and") && args && args->size() == 2)
{
const auto * left = (*args->begin())->as<ColumnExpr>();
const auto * right = (*++args->begin())->as<ColumnExpr>();
if (left && left->getType() == ExprType::FUNCTION && left->getFunctionName() == name->getName())
{
auto new_args = std::make_shared<ColumnExprList>();
for (const auto & arg : left->get(ARGS)->as<ColumnExprList &>())
new_args->push(std::static_pointer_cast<ColumnExpr>(arg));
new_args->push(std::static_pointer_cast<ColumnExpr>(*++args->begin()));
args = new_args;
}
else if (right && right->getType() == ExprType::FUNCTION && right->getFunctionName() == name->getName())
{
auto new_args = std::make_shared<ColumnExprList>();
new_args->push(std::static_pointer_cast<ColumnExpr>(*args->begin()));
for (const auto & arg : right->get(ARGS)->as<ColumnExprList &>())
new_args->push(std::static_pointer_cast<ColumnExpr>(arg));
args = new_args;
}
}
return PtrTo<ColumnExpr>(new ColumnExpr(ExprType::FUNCTION, {name, params, args}));
}
// static
PtrTo<ColumnExpr> ColumnExpr::createIdentifier(PtrTo<ColumnIdentifier> identifier)
{
return PtrTo<ColumnExpr>(new ColumnExpr(ExprType::IDENTIFIER, {identifier}));
}
// static
PtrTo<ColumnExpr> ColumnExpr::createLambda(PtrTo<List<Identifier>> params, PtrTo<ColumnExpr> expr)
{
return PtrTo<ColumnExpr>(new ColumnExpr(ExprType::LAMBDA, {params, expr}));
}
// static
PtrTo<ColumnExpr> ColumnExpr::createLiteral(PtrTo<Literal> literal)
{
return PtrTo<ColumnExpr>(new ColumnExpr(ExprType::LITERAL, {literal}));
}
// static
PtrTo<ColumnExpr> ColumnExpr::createSubquery(PtrTo<SelectUnionQuery> query, bool scalar)
{
if (scalar) query->shouldBeScalar();
return PtrTo<ColumnExpr>(new ColumnExpr(ExprType::SUBQUERY, {query}));
}
ColumnExpr::ColumnExpr(ColumnExpr::ExprType type, PtrList exprs) : INode(exprs), expr_type(type)
{
}
ASTPtr ColumnExpr::convertToOld() const
{
switch (expr_type)
{
case ExprType::ALIAS:
{
ASTPtr expr = get(EXPR)->convertToOld();
if (auto * expr_with_alias = dynamic_cast<ASTWithAlias*>(expr.get()))
expr_with_alias->setAlias(get<Identifier>(ALIAS)->getName());
else
throw std::runtime_error("Trying to convert new expression with alias to old one without alias support: " + expr->getID());
return expr;
}
case ExprType::ASTERISK:
if (has(TABLE))
{
auto expr = std::make_shared<ASTQualifiedAsterisk>();
expr->children.push_back(get(TABLE)->convertToOld());
return expr;
}
return std::make_shared<ASTAsterisk>();
case ExprType::FUNCTION:
{
auto func = std::make_shared<ASTFunction>();
func->name = get<Identifier>(NAME)->getName();
if (has(ARGS))
{
func->arguments = get(ARGS)->convertToOld();
func->children.push_back(func->arguments);
}
if (has(PARAMS))
{
func->parameters = get(PARAMS)->convertToOld();
func->children.push_back(func->parameters);
}
return func;
}
case ExprType::IDENTIFIER:
return get(IDENTIFIER)->convertToOld();
case ExprType::LAMBDA:
{
auto func = std::make_shared<ASTFunction>();
auto tuple = std::make_shared<ASTFunction>();
func->name = "lambda";
func->arguments = std::make_shared<ASTExpressionList>();
func->arguments->children.push_back(tuple);
func->arguments->children.push_back(get(LAMBDA_EXPR)->convertToOld());
func->children.push_back(func->arguments);
tuple->name = "tuple";
tuple->arguments = get(LAMBDA_ARGS)->convertToOld();
tuple->children.push_back(tuple->arguments);
return func;
}
case ExprType::LITERAL:
return get(LITERAL)->convertToOld();
case ExprType::SUBQUERY:
{
auto subquery = std::make_shared<ASTSubquery>();
subquery->children.push_back(get(SUBQUERY)->convertToOld());
return subquery;
}
}
__builtin_unreachable();
}
String ColumnExpr::toString() const
{
switch(expr_type)
{
case ExprType::LITERAL: return get(LITERAL)->toString();
default: return {};
}
__builtin_unreachable();
}
String ColumnExpr::dumpInfo() const
{
switch(expr_type)
{
case ExprType::ALIAS: return "ALIAS";
case ExprType::ASTERISK: return "ASTERISK";
case ExprType::FUNCTION: return "FUNCTION";
case ExprType::IDENTIFIER: return "IDENTIFIER";
case ExprType::LAMBDA: return "LAMBDA";
case ExprType::LITERAL: return "LITERAL";
case ExprType::SUBQUERY: return "SUBQUERY";
}
__builtin_unreachable();
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitColumnArgExpr(ClickHouseParser::ColumnArgExprContext *ctx)
{
if (ctx->columnExpr()) return visit(ctx->columnExpr());
if (ctx->columnLambdaExpr()) return visit(ctx->columnLambdaExpr());
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitColumnArgList(ClickHouseParser::ColumnArgListContext *ctx)
{
auto list = std::make_shared<ColumnExprList>();
for (auto * arg : ctx->columnArgExpr()) list->push(visit(arg));
return list;
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprAlias(ClickHouseParser::ColumnExprAliasContext *ctx)
{
if (ctx->AS()) return ColumnExpr::createAlias(visit(ctx->columnExpr()), visit(ctx->identifier()));
else return ColumnExpr::createAlias(visit(ctx->columnExpr()), visit(ctx->alias()));
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprAnd(ClickHouseParser::ColumnExprAndContext *ctx)
{
auto name = std::make_shared<Identifier>("and");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprArray(ClickHouseParser::ColumnExprArrayContext *ctx)
{
auto name = std::make_shared<Identifier>("array");
auto args = ctx->columnExprList() ? visit(ctx->columnExprList()).as<PtrTo<ColumnExprList>>() : nullptr;
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprArrayAccess(ClickHouseParser::ColumnExprArrayAccessContext *ctx)
{
auto name = std::make_shared<Identifier>("arrayElement");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprAsterisk(ClickHouseParser::ColumnExprAsteriskContext *ctx)
{
auto table = ctx->tableIdentifier() ? visit(ctx->tableIdentifier()).as<PtrTo<TableIdentifier>>() : nullptr;
return ColumnExpr::createAsterisk(table, true);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprBetween(ClickHouseParser::ColumnExprBetweenContext *ctx)
{
PtrTo<ColumnExpr> expr1, expr2;
{
auto name = std::make_shared<Identifier>(ctx->NOT() ? "lessOrEquals" : "greaterOrEquals");
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr(0)));
args->push(visit(ctx->columnExpr(1)));
expr1 = ColumnExpr::createFunction(name, nullptr, args);
}
{
auto name = std::make_shared<Identifier>(ctx->NOT() ? "greaterOrEquals" : "lessOrEquals");
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr(0)));
args->push(visit(ctx->columnExpr(2)));
expr2 = ColumnExpr::createFunction(name, nullptr, args);
}
auto name = std::make_shared<Identifier>("and");
auto args = std::make_shared<ColumnExprList>();
args->push(expr1);
args->push(expr2);
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprCase(ClickHouseParser::ColumnExprCaseContext *ctx)
{
auto has_case_expr = (ctx->ELSE() && ctx->columnExpr().size() % 2 == 0) || (!ctx->ELSE() && ctx->columnExpr().size() % 2 == 1);
auto name = std::make_shared<Identifier>(has_case_expr ? "caseWithExpression" : "multiIf");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
if (!ctx->ELSE()) args->push(ColumnExpr::createLiteral(Literal::createNull()));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprCast(ClickHouseParser::ColumnExprCastContext *ctx)
{
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr()));
args->push(ColumnExpr::createLiteral(Literal::createString(visit(ctx->columnTypeExpr()).as<PtrTo<ColumnTypeExpr>>()->toString())));
return ColumnExpr::createFunction(std::make_shared<Identifier>("cast"), nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprDate(ClickHouseParser::ColumnExprDateContext *ctx)
{
auto name = std::make_shared<Identifier>("toDate");
auto args = std::make_shared<ColumnExprList>();
args->push(ColumnExpr::createLiteral(Literal::createString(ctx->STRING_LITERAL())));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprExtract(ClickHouseParser::ColumnExprExtractContext *ctx)
{
String name;
auto args = std::make_shared<ColumnExprList>();
if (ctx->interval()->SECOND()) name = "toSecond";
else if (ctx->interval()->MINUTE()) name = "toMinute";
else if (ctx->interval()->HOUR()) name = "toHour";
else if (ctx->interval()->DAY()) name = "toDayOfMonth";
else if (ctx->interval()->WEEK())
throw Exception(
"The syntax 'EXTRACT(WEEK FROM date)' is not supported, cannot extract the number of a week", ErrorCodes::SYNTAX_ERROR);
else if (ctx->interval()->MONTH()) name = "toMonth";
else if (ctx->interval()->QUARTER()) name = "toQuarter";
else if (ctx->interval()->YEAR()) name = "toYear";
else __builtin_unreachable();
args->push(visit(ctx->columnExpr()));
return ColumnExpr::createFunction(std::make_shared<Identifier>(name), nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprFunction(ClickHouseParser::ColumnExprFunctionContext *ctx)
{
auto name = visit(ctx->identifier()).as<PtrTo<Identifier>>();
auto params = ctx->columnExprList() ? visit(ctx->columnExprList()).as<PtrTo<ColumnExprList>>() : nullptr;
auto args = ctx->columnArgList() ? visit(ctx->columnArgList()).as<PtrTo<ColumnExprList>>() : nullptr;
if (ctx->DISTINCT()) name = std::make_shared<Identifier>(name->getName() + "Distinct");
return ColumnExpr::createFunction(name, params, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprIdentifier(ClickHouseParser::ColumnExprIdentifierContext *ctx)
{
return ColumnExpr::createIdentifier(visit(ctx->columnIdentifier()));
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprInterval(ClickHouseParser::ColumnExprIntervalContext *ctx)
{
PtrTo<Identifier> name;
auto args = std::make_shared<ColumnExprList>();
if (ctx->interval()->SECOND()) name = std::make_shared<Identifier>("toIntervalSecond");
else if (ctx->interval()->MINUTE()) name = std::make_shared<Identifier>("toIntervalMinute");
else if (ctx->interval()->HOUR()) name = std::make_shared<Identifier>("toIntervalHour");
else if (ctx->interval()->DAY()) name = std::make_shared<Identifier>("toIntervalDay");
else if (ctx->interval()->WEEK()) name = std::make_shared<Identifier>("toIntervalWeek");
else if (ctx->interval()->MONTH()) name = std::make_shared<Identifier>("toIntervalMonth");
else if (ctx->interval()->QUARTER()) name = std::make_shared<Identifier>("toIntervalQuarter");
else if (ctx->interval()->YEAR()) name = std::make_shared<Identifier>("toIntervalYear");
else __builtin_unreachable();
args->push(visit(ctx->columnExpr()));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprIsNull(ClickHouseParser::ColumnExprIsNullContext *ctx)
{
auto name = std::make_shared<Identifier>(ctx->NOT() ? "isNotNull" : "isNull");
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr()));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprList(ClickHouseParser::ColumnExprListContext *ctx)
{
auto list = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnsExpr()) list->push(visit(expr));
return list;
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprLiteral(ClickHouseParser::ColumnExprLiteralContext *ctx)
{
return ColumnExpr::createLiteral(visit(ctx->literal()).as<PtrTo<Literal>>());
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprNegate(ClickHouseParser::ColumnExprNegateContext *ctx)
{
auto name = std::make_shared<Identifier>("negate");
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr()));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprNot(ClickHouseParser::ColumnExprNotContext *ctx)
{
auto name = std::make_shared<Identifier>("not");
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr()));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprOr(ClickHouseParser::ColumnExprOrContext *ctx)
{
auto name = std::make_shared<Identifier>("or");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprParens(ClickHouseParser::ColumnExprParensContext *ctx)
{
return visit(ctx->columnExpr());
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprPrecedence1(ClickHouseParser::ColumnExprPrecedence1Context *ctx)
{
PtrTo<Identifier> name;
if (ctx->ASTERISK()) name = std::make_shared<Identifier>("multiply");
else if (ctx->SLASH()) name = std::make_shared<Identifier>("divide");
else if (ctx->PERCENT()) name = std::make_shared<Identifier>("modulo");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprPrecedence2(ClickHouseParser::ColumnExprPrecedence2Context *ctx)
{
PtrTo<Identifier> name;
if (ctx->PLUS()) name = std::make_shared<Identifier>("plus");
else if (ctx->DASH()) name = std::make_shared<Identifier>("minus");
else if (ctx->CONCAT()) name = std::make_shared<Identifier>("concat");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprPrecedence3(ClickHouseParser::ColumnExprPrecedence3Context *ctx)
{
PtrTo<Identifier> name;
if (ctx->EQ_DOUBLE() || ctx->EQ_SINGLE()) name = std::make_shared<Identifier>("equals");
else if (ctx->NOT_EQ()) name = std::make_shared<Identifier>("notEquals");
else if (ctx->LE()) name = std::make_shared<Identifier>("lessOrEquals");
else if (ctx->GE()) name = std::make_shared<Identifier>("greaterOrEquals");
else if (ctx->LT()) name = std::make_shared<Identifier>("less");
else if (ctx->GT()) name = std::make_shared<Identifier>("greater");
else if (ctx->LIKE())
{
if (ctx->NOT()) name = std::make_shared<Identifier>("notLike");
else name = std::make_shared<Identifier>("like");
}
else if (ctx->ILIKE())
{
if (ctx->NOT()) name = std::make_shared<Identifier>("notILike");
else name = std::make_shared<Identifier>("ilike");
}
else if (ctx->IN())
{
if (ctx->GLOBAL())
{
if (ctx->NOT()) name = std::make_shared<Identifier>("globalNotIn");
else name = std::make_shared<Identifier>("globalIn");
}
else
{
if (ctx->NOT()) name = std::make_shared<Identifier>("notIn");
else name = std::make_shared<Identifier>("in");
}
}
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprSubquery(ClickHouseParser::ColumnExprSubqueryContext *ctx)
{
// IN-operator is special since it accepts non-scalar subqueries on the right side.
auto * parent = dynamic_cast<ClickHouseParser::ColumnExprPrecedence3Context*>(ctx->parent);
return ColumnExpr::createSubquery(visit(ctx->selectUnionStmt()), !(parent && parent->IN()));
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprSubstring(ClickHouseParser::ColumnExprSubstringContext *ctx)
{
auto name = std::make_shared<Identifier>("substring");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprTernaryOp(ClickHouseParser::ColumnExprTernaryOpContext *ctx)
{
auto name = std::make_shared<Identifier>("if");
auto args = std::make_shared<ColumnExprList>();
for (auto * expr : ctx->columnExpr()) args->push(visit(expr));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprTimestamp(ClickHouseParser::ColumnExprTimestampContext *ctx)
{
auto name = std::make_shared<Identifier>("toDateTime");
auto args = std::make_shared<ColumnExprList>();
args->push(ColumnExpr::createLiteral(Literal::createString(ctx->STRING_LITERAL())));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprTrim(ClickHouseParser::ColumnExprTrimContext *ctx)
{
auto name = std::make_shared<Identifier>("trim");
auto args = std::make_shared<ColumnExprList>();
auto params = std::make_shared<ColumnParamList>();
args->push(visit(ctx->columnExpr()));
// TODO: params->append(Literal::createString(???));
params->push(ColumnExpr::createLiteral(Literal::createString(ctx->STRING_LITERAL())));
return ColumnExpr::createFunction(name, params, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprTuple(ClickHouseParser::ColumnExprTupleContext *ctx)
{
auto name = std::make_shared<Identifier>("tuple");
auto args = visit(ctx->columnExprList()).as<PtrTo<ColumnExprList>>();
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnExprTupleAccess(ClickHouseParser::ColumnExprTupleAccessContext *ctx)
{
auto name = std::make_shared<Identifier>("tupleElement");
auto args = std::make_shared<ColumnExprList>();
args->push(visit(ctx->columnExpr()));
args->push(ColumnExpr::createLiteral(Literal::createNumber(ctx->DECIMAL_LITERAL())));
return ColumnExpr::createFunction(name, nullptr, args);
}
antlrcpp::Any ParseTreeVisitor::visitColumnLambdaExpr(ClickHouseParser::ColumnLambdaExprContext *ctx)
{
auto params = std::make_shared<List<Identifier>>();
for (auto * id : ctx->identifier()) params->push(visit(id));
return ColumnExpr::createLambda(params, visit(ctx->columnExpr()));
}
antlrcpp::Any ParseTreeVisitor::visitColumnsExprAsterisk(ClickHouseParser::ColumnsExprAsteriskContext *ctx)
{
auto table = ctx->tableIdentifier() ? visit(ctx->tableIdentifier()).as<PtrTo<TableIdentifier>>() : nullptr;
return ColumnExpr::createAsterisk(table, false);
}
antlrcpp::Any ParseTreeVisitor::visitColumnsExprSubquery(ClickHouseParser::ColumnsExprSubqueryContext *ctx)
{
return ColumnExpr::createSubquery(visit(ctx->selectUnionStmt()), false);
}
antlrcpp::Any ParseTreeVisitor::visitColumnsExprColumn(ClickHouseParser::ColumnsExprColumnContext *ctx)
{
return visit(ctx->columnExpr());
}
}

View File

@ -0,0 +1,82 @@
#pragma once
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
namespace DB::AST
{
class ColumnExpr : public INode
{
public:
static PtrTo<ColumnExpr> createAlias(PtrTo<ColumnExpr> expr, PtrTo<Identifier> alias);
static PtrTo<ColumnExpr> createAsterisk(PtrTo<TableIdentifier> identifier, bool single_column);
static PtrTo<ColumnExpr> createFunction(PtrTo<Identifier> name, PtrTo<ColumnParamList> params, PtrTo<ColumnExprList> args);
static PtrTo<ColumnExpr> createIdentifier(PtrTo<ColumnIdentifier> identifier);
static PtrTo<ColumnExpr> createLambda(PtrTo<List<Identifier>> params, PtrTo<ColumnExpr> expr);
static PtrTo<ColumnExpr> createLiteral(PtrTo<Literal> literal);
static PtrTo<ColumnExpr> createSubquery(PtrTo<SelectUnionQuery> query, bool scalar);
enum class ExprType
{
ALIAS,
ASTERISK,
FUNCTION,
IDENTIFIER,
LAMBDA,
LITERAL,
SUBQUERY,
};
auto getType() const { return expr_type; };
// FUNCTION
auto getFunctionName() const { return get<Identifier>(NAME)->getName(); }
auto argumentsBegin() const { return has(ARGS) ? get<ColumnExprList>(ARGS)->begin() : end(); }
auto argumentsEnd() const { return has(ARGS) ? get<ColumnExprList>(ARGS)->end() : end(); }
// LITERAL
auto getLiteral() const { return std::static_pointer_cast<Literal>(get(LITERAL)); }
ASTPtr convertToOld() const override;
String toString() const override;
private:
enum ChildIndex : UInt8
{
// ALIAS
EXPR = 0, // ColumnExpr
ALIAS = 1, // Identifier
// ASTERISK
TABLE = 0, // TableIdentifier (optional)
// IDENTIFIER
IDENTIFIER = 0, // ColumnIdentifier
// FUNCTION
NAME = 0, // Identifier
PARAMS = 1, // ColumnParamList (optional)
ARGS = 2, // ColumnExprList (optional)
// LAMBDA
LAMBDA_ARGS = 0,
LAMBDA_EXPR = 1,
// LITERAL
LITERAL = 0,
// SUBQUERY
SUBQUERY = 0,
};
const ExprType expr_type;
bool expect_single_column = false;
ColumnExpr(ExprType type, PtrList exprs);
String dumpInfo() const override;
};
}

View File

@ -0,0 +1,166 @@
#include <Parsers/New/AST/ColumnTypeExpr.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTNameTypePair.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
EnumValue::EnumValue(PtrTo<StringLiteral> name, PtrTo<NumberLiteral> value) : INode{name, value}
{
}
ASTPtr EnumValue::convertToOld() const
{
auto func = std::make_shared<ASTFunction>();
func->name = "equals";
func->arguments = std::make_shared<ASTExpressionList>();
func->arguments->children.push_back(get(NAME)->convertToOld());
func->arguments->children.push_back(get(VALUE)->convertToOld());
func->children.push_back(func->arguments);
return func;
}
String EnumValue::toString() const
{
return fmt::format("{} = {}", get(NAME)->toString(), get(VALUE)->toString());
}
// static
PtrTo<ColumnTypeExpr> ColumnTypeExpr::createSimple(PtrTo<Identifier> identifier)
{
return PtrTo<ColumnTypeExpr>(new ColumnTypeExpr(ExprType::SIMPLE, {identifier}));
}
// static
PtrTo<ColumnTypeExpr> ColumnTypeExpr::createNamed(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExpr> type)
{
return PtrTo<ColumnTypeExpr>(new ColumnTypeExpr(ExprType::NAMED, {identifier, type}));
}
// static
PtrTo<ColumnTypeExpr> ColumnTypeExpr::createComplex(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExprList> list)
{
return PtrTo<ColumnTypeExpr>(new ColumnTypeExpr(ExprType::COMPLEX, {identifier, list}));
}
// static
PtrTo<ColumnTypeExpr> ColumnTypeExpr::createEnum(PtrTo<Identifier> identifier, PtrTo<EnumValueList> list)
{
return PtrTo<ColumnTypeExpr>(new ColumnTypeExpr(ExprType::ENUM, {identifier, list}));
}
// static
PtrTo<ColumnTypeExpr> ColumnTypeExpr::createParam(PtrTo<Identifier> identifier, PtrTo<ColumnParamList> list)
{
return PtrTo<ColumnTypeExpr>(new ColumnTypeExpr(ExprType::PARAM, {identifier, list}));
}
// static
PtrTo<ColumnTypeExpr> ColumnTypeExpr::createNested(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExprList> list)
{
// TODO: assert that |list| must contain only expressions of NAMED type
return PtrTo<ColumnTypeExpr>(new ColumnTypeExpr(ExprType::NESTED, {identifier, list}));
}
ColumnTypeExpr::ColumnTypeExpr(ExprType type, PtrList exprs) : INode(exprs), expr_type(type)
{
}
ASTPtr ColumnTypeExpr::convertToOld() const
{
if (expr_type == ExprType::NAMED)
{
auto pair = std::make_shared<ASTNameTypePair>();
pair->name = get<Identifier>(NAME)->getName();
pair->type = get(TYPE)->convertToOld();
pair->children.push_back(pair->type);
return pair;
}
auto func = std::make_shared<ASTFunction>();
func->name = get<Identifier>(NAME)->getName();
func->no_empty_args = true;
if (expr_type != ExprType::SIMPLE && has(LIST))
{
func->arguments = get(LIST)->convertToOld();
func->children.push_back(func->arguments);
}
return func;
}
String ColumnTypeExpr::toString() const
{
switch(expr_type)
{
case ExprType::SIMPLE:
return get(NAME)->toString();
case ExprType::NAMED:
return get(NAME)->toString() + " " + get(TYPE)->toString();
case ExprType::COMPLEX:
case ExprType::ENUM:
case ExprType::PARAM:
case ExprType::NESTED:
return get(NAME)->toString() + "(" + (has(LIST) ? get(LIST)->toString() : "") + ")";
}
__builtin_unreachable();
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitColumnTypeExprSimple(ClickHouseParser::ColumnTypeExprSimpleContext *ctx)
{
return ColumnTypeExpr::createSimple(visit(ctx->identifier()));
}
antlrcpp::Any ParseTreeVisitor::visitColumnTypeExprParam(ClickHouseParser::ColumnTypeExprParamContext *ctx)
{
auto list = ctx->columnExprList() ? visit(ctx->columnExprList()).as<PtrTo<ColumnExprList>>() : nullptr;
return ColumnTypeExpr::createParam(visit(ctx->identifier()), list);
}
antlrcpp::Any ParseTreeVisitor::visitColumnTypeExprEnum(ClickHouseParser::ColumnTypeExprEnumContext *ctx)
{
auto list = std::make_shared<EnumValueList>();
for (auto * value : ctx->enumValue()) list->push(visit(value));
return ColumnTypeExpr::createEnum(visit(ctx->identifier()), list);
}
antlrcpp::Any ParseTreeVisitor::visitColumnTypeExprComplex(ClickHouseParser::ColumnTypeExprComplexContext *ctx)
{
auto list = std::make_shared<ColumnTypeExprList>();
for (auto * expr : ctx->columnTypeExpr()) list->push(visit(expr));
return ColumnTypeExpr::createComplex(visit(ctx->identifier()), list);
}
antlrcpp::Any ParseTreeVisitor::visitColumnTypeExprNested(ClickHouseParser::ColumnTypeExprNestedContext *ctx)
{
auto list = std::make_shared<ColumnTypeExprList>();
for (size_t i = 0; i < ctx->columnTypeExpr().size(); ++i)
list->push(ColumnTypeExpr::createNamed(visit(ctx->identifier(i + 1)), visit(ctx->columnTypeExpr(i))));
return ColumnTypeExpr::createNested(visit(ctx->identifier(0)), list);
}
antlrcpp::Any ParseTreeVisitor::visitEnumValue(ClickHouseParser::EnumValueContext *ctx)
{
return std::make_shared<EnumValue>(Literal::createString(ctx->STRING_LITERAL()), visit(ctx->numberLiteral()));
}
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <Parsers/New/AST/INode.h>
#include <list>
namespace DB::AST
{
class EnumValue : public INode
{
public:
EnumValue(PtrTo<StringLiteral> name, PtrTo<NumberLiteral> value);
ASTPtr convertToOld() const override;
String toString() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // StringLiteral
VALUE = 1, // NumberLiteral
};
};
class ColumnTypeExpr : public INode
{
public:
static PtrTo<ColumnTypeExpr> createSimple(PtrTo<Identifier> identifier);
static PtrTo<ColumnTypeExpr> createNamed(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExpr> type);
static PtrTo<ColumnTypeExpr> createComplex(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExprList> list);
static PtrTo<ColumnTypeExpr> createEnum(PtrTo<Identifier> identifier, PtrTo<EnumValueList> list);
static PtrTo<ColumnTypeExpr> createParam(PtrTo<Identifier> identifier, PtrTo<ColumnParamList> list);
static PtrTo<ColumnTypeExpr> createNested(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExprList> list);
ASTPtr convertToOld() const override;
String toString() const override;
private:
enum class ExprType
{
SIMPLE,
NAMED,
COMPLEX,
ENUM,
PARAM,
NESTED,
};
enum ChildIndex : UInt8
{
NAME = 0, // Identifier
TYPE = 1, // ColumnTypeExpr
LIST = 1, // depends on |expr_type|
};
ExprType expr_type;
ColumnTypeExpr(ExprType type, PtrList exprs);
};
}

View File

@ -0,0 +1,51 @@
#include <Parsers/New/AST/CreateDatabaseQuery.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/New/AST/EngineExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
CreateDatabaseQuery::CreateDatabaseQuery(
PtrTo<ClusterClause> cluster, bool if_not_exists_, PtrTo<DatabaseIdentifier> identifier, PtrTo<EngineExpr> expr)
: DDLQuery(cluster, {identifier, expr}), if_not_exists(if_not_exists_)
{
}
ASTPtr CreateDatabaseQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
query->if_not_exists = if_not_exists;
query->database = get<DatabaseIdentifier>(NAME)->getName();
query->cluster = cluster_name;
if (has(ENGINE))
{
auto engine = std::make_shared<ASTStorage>();
engine->set(engine->engine, get(ENGINE)->convertToOld());
query->set(query->storage, engine);
}
// TODO: query->uuid
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitCreateDatabaseStmt(ClickHouseParser::CreateDatabaseStmtContext *ctx)
{
auto engine = ctx->engineExpr() ? visit(ctx->engineExpr()).as<PtrTo<EngineExpr>>() : nullptr;
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
return std::make_shared<CreateDatabaseQuery>(cluster, !!ctx->IF(), visit(ctx->databaseIdentifier()), engine);
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class CreateDatabaseQuery: public DDLQuery
{
public:
CreateDatabaseQuery(PtrTo<ClusterClause> cluster, bool if_not_exists, PtrTo<DatabaseIdentifier> identifier, PtrTo<EngineExpr> expr);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // DatabaseIdentifier
ENGINE = 1, // EngineExpr (optional)
};
const bool if_not_exists;
};
}

View File

@ -0,0 +1,361 @@
#include <Parsers/New/AST/CreateDictionaryQuery.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/New/AST/ColumnTypeExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/AST/SettingExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
#include <Poco/String.h>
namespace DB::ErrorCodes
{
extern const int SYNTAX_ERROR;
}
namespace DB::AST
{
// DictionaryAttributeExpr
DictionaryAttributeExpr::DictionaryAttributeExpr(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExpr> type) : INode(MAX_INDEX)
{
set(NAME, identifier);
set(TYPE, type);
}
void DictionaryAttributeExpr::setDefaultClause(PtrTo<Literal> literal)
{
set(DEFAULT, literal);
}
void DictionaryAttributeExpr::setExpressionClause(PtrTo<ColumnExpr> expr)
{
set(EXPRESSION, expr);
}
ASTPtr DictionaryAttributeExpr::convertToOld() const
{
auto expr = std::make_shared<ASTDictionaryAttributeDeclaration>();
expr->name = get<Identifier>(NAME)->getName();
if (has(TYPE))
{
expr->type = get(TYPE)->convertToOld();
expr->children.push_back(expr->type);
}
if (has(DEFAULT))
{
expr->default_value = get(DEFAULT)->convertToOld();
expr->children.push_back(expr->default_value);
}
if (has(EXPRESSION))
{
expr->expression = get(EXPRESSION)->convertToOld();
expr->children.push_back(expr->expression);
}
expr->hierarchical = hierarchical;
expr->injective = injective;
expr->is_object_id = is_object_id;
return expr;
}
// DictionaryArgExpr
DictionaryArgExpr::DictionaryArgExpr(PtrTo<Identifier> identifier, PtrTo<ColumnExpr> expr) : INode{identifier, expr}
{
if (expr->getType() != ColumnExpr::ExprType::LITERAL && expr->getType() != ColumnExpr::ExprType::IDENTIFIER
&& expr->getType() != ColumnExpr::ExprType::FUNCTION)
throw DB::Exception(ErrorCodes::SYNTAX_ERROR, "Expected literal, identifier or function");
}
ASTPtr DictionaryArgExpr::convertToOld() const
{
auto expr = std::make_shared<ASTPair>(false); // FIXME: always true?
// TODO: probably there are more variants to parse.
expr->first = Poco::toLower(get<Identifier>(KEY)->getName());
expr->set(expr->second, get(VALUE)->convertToOld());
return expr;
}
// SourceClause
SourceClause::SourceClause(PtrTo<Identifier> identifier, PtrTo<DictionaryArgList> list) : INode{identifier, list}
{
}
ASTPtr SourceClause::convertToOld() const
{
auto clause = std::make_shared<ASTFunctionWithKeyValueArguments>(true); // FIXME: always true?
clause->name = Poco::toLower(get<Identifier>(NAME)->getName());
if (has(ARGS))
{
clause->elements = get(ARGS)->convertToOld();
clause->children.push_back(clause->elements);
}
return clause;
}
// LifetimeClause
LifetimeClause::LifetimeClause(PtrTo<NumberLiteral> max, PtrTo<NumberLiteral> min) : INode{max, min}
{
}
ASTPtr LifetimeClause::convertToOld() const
{
auto clause = std::make_shared<ASTDictionaryLifetime>();
clause->max_sec = get(MAX)->convertToOld()->as<ASTLiteral>()->value.get<UInt64>();
if (has(MIN)) clause->min_sec = get(MIN)->convertToOld()->as<ASTLiteral>()->value.get<UInt64>();
return clause;
}
// LayoutClause
LayoutClause::LayoutClause(PtrTo<Identifier> identifier, PtrTo<DictionaryArgList> list) : INode{identifier, list}
{
}
ASTPtr LayoutClause::convertToOld() const
{
auto clause = std::make_shared<ASTDictionaryLayout>();
clause->layout_type = Poco::toLower(get<Identifier>(NAME)->getName());
clause->has_brackets = true; // FIXME: maybe not?
if (has(ARGS)) clause->set(clause->parameters, get(ARGS)->convertToOld());
return clause;
}
// RangeClause
RangeClause::RangeClause(PtrTo<Identifier> max, PtrTo<Identifier> min) : INode{max, min}
{
}
ASTPtr RangeClause::convertToOld() const
{
auto clause = std::make_shared<ASTDictionaryRange>();
clause->max_attr_name = get<Identifier>(MAX)->getName();
clause->min_attr_name = get<Identifier>(MIN)->getName();
return clause;
}
// DictionarySettingsClause
DictionarySettingsClause::DictionarySettingsClause(PtrTo<SettingExprList> list) : INode{list}
{
}
ASTPtr DictionarySettingsClause::convertToOld() const
{
auto clause = std::make_shared<ASTDictionarySettings>();
for (const auto & child : get(LIST)->as<SettingExprList &>())
{
const auto * setting = child->as<SettingExpr>();
clause->changes.emplace_back(setting->getName()->getName(), setting->getValue()->convertToOld()->as<ASTLiteral>()->value);
}
return clause;
}
// DictionaryEngineClause
DictionaryEngineClause::DictionaryEngineClause(PtrTo<DictionaryPrimaryKeyClause> clause) : INode(MAX_INDEX)
{
set(PRIMARY_KEY, clause);
}
void DictionaryEngineClause::setSourceClause(PtrTo<SourceClause> clause)
{
set(SOURCE, clause);
}
void DictionaryEngineClause::setLifetimeClause(PtrTo<LifetimeClause> clause)
{
set(LIFETIME, clause);
}
void DictionaryEngineClause::setLayoutClause(PtrTo<LayoutClause> clause)
{
set(LAYOUT, clause);
}
void DictionaryEngineClause::setRangeClause(PtrTo<RangeClause> clause)
{
set(RANGE, clause);
}
void DictionaryEngineClause::setSettingsClause(PtrTo<DictionarySettingsClause> clause)
{
set(SETTINGS, clause);
}
ASTPtr DictionaryEngineClause::convertToOld() const
{
auto clause = std::make_shared<ASTDictionary>();
if (has(PRIMARY_KEY)) clause->set(clause->primary_key, get(PRIMARY_KEY)->convertToOld());
if (has(SOURCE)) clause->set(clause->source, get(SOURCE)->convertToOld());
if (has(LIFETIME)) clause->set(clause->lifetime, get(LIFETIME)->convertToOld());
if (has(LAYOUT)) clause->set(clause->layout, get(LAYOUT)->convertToOld());
if (has(RANGE)) clause->set(clause->range, get(RANGE)->convertToOld());
if (has(SETTINGS)) clause->set(clause->dict_settings, get(SETTINGS)->convertToOld());
return clause;
}
// CreateDictionaryQuery
CreateDictionaryQuery::CreateDictionaryQuery(
PtrTo<ClusterClause> cluster,
bool attach_,
bool if_not_exists_,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<DictionarySchemaClause> schema,
PtrTo<DictionaryEngineClause> engine)
: DDLQuery(cluster, {identifier, uuid, schema, engine}), attach(attach_), if_not_exists(if_not_exists_)
{
}
ASTPtr CreateDictionaryQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
{
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid
= has(UUID) ? parseFromString<DB::UUID>(get(UUID)->convertToOld()->as<ASTLiteral>()->value.get<String>()) : table_id.uuid;
}
query->cluster = cluster_name;
query->is_dictionary = true;
query->attach = attach;
query->if_not_exists = if_not_exists;
query->set(query->dictionary_attributes_list, get(SCHEMA)->convertToOld());
query->set(query->dictionary, get(ENGINE)->convertToOld());
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitCreateDictionaryStmt(ClickHouseParser::CreateDictionaryStmtContext *ctx)
{
auto uuid = ctx->uuidClause() ? visit(ctx->uuidClause()).as<PtrTo<UUIDClause>>() : nullptr;
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto schema = ctx->dictionarySchemaClause() ? visit(ctx->dictionarySchemaClause()).as<PtrTo<DictionarySchemaClause>>() : nullptr;
auto engine = ctx->dictionaryEngineClause() ? visit(ctx->dictionaryEngineClause()).as<PtrTo<DictionaryEngineClause>>() : nullptr;
return std::make_shared<CreateDictionaryQuery>(
cluster, !!ctx->ATTACH(), !!ctx->IF(), visit(ctx->tableIdentifier()), uuid, schema, engine);
}
antlrcpp::Any ParseTreeVisitor::visitDictionaryArgExpr(ClickHouseParser::DictionaryArgExprContext *ctx)
{
PtrTo<ColumnExpr> expr;
if (ctx->literal()) expr = ColumnExpr::createLiteral(visit(ctx->literal()));
else if (ctx->LPAREN()) expr = ColumnExpr::createFunction(visit(ctx->identifier(1)), nullptr, nullptr);
else expr = ColumnExpr::createIdentifier(visit(ctx->identifier(1)));
return std::make_shared<DictionaryArgExpr>(visit(ctx->identifier(0)), expr);
}
antlrcpp::Any ParseTreeVisitor::visitDictionaryAttrDfnt(ClickHouseParser::DictionaryAttrDfntContext *ctx)
{
auto expr = std::make_shared<DictionaryAttributeExpr>(visit(ctx->identifier()), visit(ctx->columnTypeExpr()));
if (!ctx->DEFAULT().empty()) expr->setDefaultClause(visit(ctx->literal(0)));
if (!ctx->EXPRESSION().empty()) expr->setExpressionClause(visit(ctx->columnExpr(0)));
if (!ctx->HIERARCHICAL().empty()) expr->setHierarchicalFlag();
if (!ctx->INJECTIVE().empty()) expr->setInjectiveFlag();
if (!ctx->IS_OBJECT_ID().empty()) expr->setIsObjectIdFlag();
return expr;
}
antlrcpp::Any ParseTreeVisitor::visitDictionaryEngineClause(ClickHouseParser::DictionaryEngineClauseContext *ctx)
{
auto primary_key
= ctx->dictionaryPrimaryKeyClause() ? visit(ctx->dictionaryPrimaryKeyClause()).as<PtrTo<DictionaryPrimaryKeyClause>>() : nullptr;
auto clause = std::make_shared<DictionaryEngineClause>(primary_key);
if (!ctx->sourceClause().empty()) clause->setSourceClause(visit(ctx->sourceClause(0)));
if (!ctx->lifetimeClause().empty()) clause->setLifetimeClause(visit(ctx->lifetimeClause(0)));
if (!ctx->layoutClause().empty()) clause->setLayoutClause(visit(ctx->layoutClause(0)));
if (!ctx->rangeClause().empty()) clause->setRangeClause(visit(ctx->rangeClause(0)));
if (!ctx->dictionarySettingsClause().empty()) clause->setSettingsClause(visit(ctx->dictionarySettingsClause(0)));
return clause;
}
antlrcpp::Any ParseTreeVisitor::visitDictionaryPrimaryKeyClause(ClickHouseParser::DictionaryPrimaryKeyClauseContext *ctx)
{
return std::make_shared<DictionaryPrimaryKeyClause>(visit(ctx->columnExprList()).as<PtrTo<ColumnExprList>>());
}
antlrcpp::Any ParseTreeVisitor::visitDictionarySchemaClause(ClickHouseParser::DictionarySchemaClauseContext *ctx)
{
auto list = std::make_shared<DictionaryAttributeList>();
for (auto * attr : ctx->dictionaryAttrDfnt()) list->push(visit(attr));
return std::make_shared<DictionarySchemaClause>(list);
}
antlrcpp::Any ParseTreeVisitor::visitDictionarySettingsClause(ClickHouseParser::DictionarySettingsClauseContext *ctx)
{
return std::make_shared<DictionarySettingsClause>(visit(ctx->settingExprList()).as<PtrTo<SettingExprList>>());
}
antlrcpp::Any ParseTreeVisitor::visitLayoutClause(ClickHouseParser::LayoutClauseContext *ctx)
{
auto list = ctx->dictionaryArgExpr().empty() ? nullptr : std::make_shared<DictionaryArgList>();
for (auto * arg : ctx->dictionaryArgExpr()) list->push(visit(arg));
return std::make_shared<LayoutClause>(visit(ctx->identifier()), list);
}
antlrcpp::Any ParseTreeVisitor::visitLifetimeClause(ClickHouseParser::LifetimeClauseContext *ctx)
{
if (ctx->DECIMAL_LITERAL().size() == 1) return std::make_shared<LifetimeClause>(Literal::createNumber(ctx->DECIMAL_LITERAL(0)));
if (ctx->MAX()->getSymbol()->getTokenIndex() < ctx->MIN()->getSymbol()->getTokenIndex())
return std::make_shared<LifetimeClause>(
Literal::createNumber(ctx->DECIMAL_LITERAL(0)), Literal::createNumber(ctx->DECIMAL_LITERAL(1)));
else
return std::make_shared<LifetimeClause>(
Literal::createNumber(ctx->DECIMAL_LITERAL(1)), Literal::createNumber(ctx->DECIMAL_LITERAL(0)));
}
antlrcpp::Any ParseTreeVisitor::visitRangeClause(ClickHouseParser::RangeClauseContext *ctx)
{
if (ctx->MAX()->getSymbol()->getTokenIndex() < ctx->MIN()->getSymbol()->getTokenIndex())
return std::make_shared<RangeClause>(visit(ctx->identifier(0)), visit(ctx->identifier(1)));
else
return std::make_shared<RangeClause>(visit(ctx->identifier(1)), visit(ctx->identifier(0)));
}
antlrcpp::Any ParseTreeVisitor::visitSourceClause(ClickHouseParser::SourceClauseContext *ctx)
{
auto list = ctx->dictionaryArgExpr().empty() ? nullptr : std::make_shared<DictionaryArgList>();
for (auto * arg : ctx->dictionaryArgExpr()) list->push(visit(arg));
return std::make_shared<SourceClause>(visit(ctx->identifier()), list);
}
}

View File

@ -0,0 +1,183 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class DictionaryAttributeExpr : public INode
{
public:
DictionaryAttributeExpr(PtrTo<Identifier> identifier, PtrTo<ColumnTypeExpr> type);
void setDefaultClause(PtrTo<Literal> literal);
void setExpressionClause(PtrTo<ColumnExpr> expr);
void setHierarchicalFlag() { hierarchical = true; }
void setInjectiveFlag() { injective = true; }
void setIsObjectIdFlag() { is_object_id = true; }
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // Identifier
TYPE, // ColumnTypeExpr
DEFAULT, // Literal (optional)
EXPRESSION, // ColumnExpr (optional)
MAX_INDEX,
};
bool hierarchical = false, injective = false, is_object_id = false;
};
using DictionaryPrimaryKeyClause = SimpleClause<ColumnExprList>;
using DictionarySchemaClause = SimpleClause<DictionaryAttributeList>;
class DictionaryArgExpr : public INode
{
public:
explicit DictionaryArgExpr(PtrTo<Identifier> identifier, PtrTo<ColumnExpr> expr);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
KEY = 0, // Identifier
VALUE, // ColumnExpr: literal, identifier or function
};
};
class SourceClause : public INode
{
public:
SourceClause(PtrTo<Identifier> identifier, PtrTo<DictionaryArgList> list);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // Identifier
ARGS = 1, // DictionaryArgList (optional)
};
};
class LifetimeClause : public INode
{
public:
explicit LifetimeClause(PtrTo<NumberLiteral> max, PtrTo<NumberLiteral> min = nullptr);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
MAX = 0, // NumberLiteral
MIN, // NumberLiteral (optional)
};
};
class LayoutClause : public INode
{
public:
LayoutClause(PtrTo<Identifier> identifier, PtrTo<DictionaryArgList> list);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // Identifier
ARGS = 1, // DictionaryArgList (optional)
};
};
class RangeClause : public INode
{
public:
RangeClause(PtrTo<Identifier> max, PtrTo<Identifier> min);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
MAX = 0, // Identifier
MIN, // Identifier
};
};
class DictionarySettingsClause : public INode
{
public:
explicit DictionarySettingsClause(PtrTo<SettingExprList> list);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
LIST = 0, // SettingExprList
};
};
class DictionaryEngineClause : public INode
{
public:
explicit DictionaryEngineClause(PtrTo<DictionaryPrimaryKeyClause> clause);
void setSourceClause(PtrTo<SourceClause> clause);
void setLifetimeClause(PtrTo<LifetimeClause> clause);
void setLayoutClause(PtrTo<LayoutClause> clause);
void setRangeClause(PtrTo<RangeClause> clause);
void setSettingsClause(PtrTo<DictionarySettingsClause> clause);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
PRIMARY_KEY = 0, // DictionaryPrimaryKeyClause
SOURCE, // SourceClause (optional)
LIFETIME, // LifetimeClause (optional)
LAYOUT, // LayoutClause (optional)
RANGE, // RangeClause (optional)
SETTINGS, // DictionarySettingsClause (optional)
MAX_INDEX,
};
};
class CreateDictionaryQuery : public DDLQuery
{
public:
CreateDictionaryQuery(
PtrTo<ClusterClause> cluster,
bool attach,
bool if_not_exists,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<DictionarySchemaClause> schema,
PtrTo<DictionaryEngineClause> engine);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
UUID, // UUIDClause (optional)
SCHEMA, // DictionarySchemaClause
ENGINE, // DictionaryEngineClause
};
const bool attach, if_not_exists;
};
}

View File

@ -0,0 +1,87 @@
#include <Parsers/New/AST/CreateLiveViewQuery.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/New/AST/CreateTableQuery.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
CreateLiveViewQuery::CreateLiveViewQuery(
PtrTo<ClusterClause> cluster,
bool attach_,
bool if_not_exists_,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<NumberLiteral> timeout,
PtrTo<DestinationClause> destination,
PtrTo<TableSchemaClause> schema,
PtrTo<SelectUnionQuery> query)
: DDLQuery(cluster, {identifier, uuid, timeout, destination, schema, query}), attach(attach_), if_not_exists(if_not_exists_)
{
}
ASTPtr CreateLiveViewQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
{
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid
= has(UUID) ? parseFromString<DB::UUID>(get(UUID)->convertToOld()->as<ASTLiteral>()->value.get<String>()) : table_id.uuid;
}
if (has(TIMEOUT))
query->live_view_timeout.emplace(get(TIMEOUT)->convertToOld()->as<ASTLiteral>()->value.get<UInt64>());
if (has(DESTINATION))
query->to_table_id = getTableIdentifier(get(DESTINATION)->convertToOld());
if (has(SCHEMA))
{
assert(get<TableSchemaClause>(SCHEMA)->getType() == TableSchemaClause::ClauseType::DESCRIPTION);
query->set(query->columns_list, get(SCHEMA)->convertToOld());
}
query->attach = attach;
query->if_not_exists = if_not_exists;
query->is_live_view = true;
query->set(query->select, get(SUBQUERY)->convertToOld());
query->cluster = cluster_name;
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitCreateLiveViewStmt(ClickHouseParser::CreateLiveViewStmtContext *ctx)
{
auto uuid = ctx->uuidClause() ? visit(ctx->uuidClause()).as<PtrTo<UUIDClause>>() : nullptr;
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto timeout = ctx->DECIMAL_LITERAL() ? Literal::createNumber(ctx->DECIMAL_LITERAL()) : nullptr;
auto destination = ctx->destinationClause() ? visit(ctx->destinationClause()).as<PtrTo<DestinationClause>>() : nullptr;
auto schema = ctx->tableSchemaClause() ? visit(ctx->tableSchemaClause()).as<PtrTo<TableSchemaClause>>() : nullptr;
if (ctx->TIMEOUT() && !timeout) timeout = Literal::createNumber(std::to_string(DEFAULT_TEMPORARY_LIVE_VIEW_TIMEOUT_SEC));
return std::make_shared<CreateLiveViewQuery>(
cluster,
!!ctx->ATTACH(),
!!ctx->IF(),
visit(ctx->tableIdentifier()),
uuid,
timeout,
destination,
schema,
visit(ctx->subqueryClause()));
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class CreateLiveViewQuery : public DDLQuery
{
public:
CreateLiveViewQuery(
PtrTo<ClusterClause> cluster,
bool attach,
bool if_not_exists,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<NumberLiteral> timeout,
PtrTo<DestinationClause> destination,
PtrTo<TableSchemaClause> schema,
PtrTo<SelectUnionQuery> query);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
UUID, // UUIDClause (optional)
TIMEOUT, // NumberLiteral (optional)
DESTINATION, // DestinationClause (optional)
SCHEMA, // TableSchemaClause (optional)
SUBQUERY, // SelectUnionQuery
};
const bool attach, if_not_exists;
};
}

View File

@ -0,0 +1,100 @@
#include <Parsers/New/AST/CreateMaterializedViewQuery.h>
#include <IO/ReadHelpers.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/New/AST/CreateTableQuery.h>
#include <Parsers/New/AST/EngineExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
CreateMaterializedViewQuery::CreateMaterializedViewQuery(
PtrTo<ClusterClause> cluster,
bool attach_,
bool if_not_exists_,
bool populate_,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<TableSchemaClause> schema,
PtrTo<DestinationClause> destination,
PtrTo<EngineClause> engine,
PtrTo<SelectUnionQuery> query)
: DDLQuery(cluster, {identifier, uuid, schema, destination, engine, query})
, attach(attach_)
, if_not_exists(if_not_exists_)
, populate(populate_)
{
assert(!destination != !engine);
}
ASTPtr CreateMaterializedViewQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
{
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid
= has(UUID) ? parseFromString<DB::UUID>(get(UUID)->convertToOld()->as<ASTLiteral>()->value.get<String>()) : table_id.uuid;
}
if (has(DESTINATION))
query->to_table_id = getTableIdentifier(get(DESTINATION)->convertToOld());
else if (has(ENGINE))
{
query->set(query->storage, get(ENGINE)->convertToOld());
query->is_populate = populate;
}
if (has(SCHEMA))
{
assert(get<TableSchemaClause>(SCHEMA)->getType() == TableSchemaClause::ClauseType::DESCRIPTION);
query->set(query->columns_list, get(SCHEMA)->convertToOld());
}
query->attach = attach;
query->if_not_exists = if_not_exists;
query->is_materialized_view = true;
query->set(query->select, get(SUBQUERY)->convertToOld());
query->cluster = cluster_name;
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitCreateMaterializedViewStmt(ClickHouseParser::CreateMaterializedViewStmtContext *ctx)
{
auto uuid = ctx->uuidClause() ? visit(ctx->uuidClause()).as<PtrTo<UUIDClause>>() : nullptr;
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto schema = ctx->tableSchemaClause() ? visit(ctx->tableSchemaClause()).as<PtrTo<TableSchemaClause>>() : nullptr;
auto engine = ctx->engineClause() ? visit(ctx->engineClause()).as<PtrTo<EngineClause>>() : nullptr;
auto destination = ctx->destinationClause() ? visit(ctx->destinationClause()).as<PtrTo<DestinationClause>>() : nullptr;
return std::make_shared<CreateMaterializedViewQuery>(
cluster,
!!ctx->ATTACH(),
!!ctx->IF(),
!!ctx->POPULATE(),
visit(ctx->tableIdentifier()),
uuid,
schema,
destination,
engine,
visit(ctx->subqueryClause()));
}
antlrcpp::Any ParseTreeVisitor::visitDestinationClause(ClickHouseParser::DestinationClauseContext *ctx)
{
return std::make_shared<DestinationClause>(visit(ctx->tableIdentifier()).as<PtrTo<TableIdentifier>>());
}
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class CreateMaterializedViewQuery : public DDLQuery
{
public:
CreateMaterializedViewQuery(
PtrTo<ClusterClause> cluster,
bool attach,
bool if_not_exists,
bool populate,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<TableSchemaClause> schema,
PtrTo<DestinationClause> destination,
PtrTo<EngineClause> engine,
PtrTo<SelectUnionQuery> query);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
UUID, // UUIDClause (optional)
SCHEMA, // TableSchemaClause (optional)
DESTINATION, // DestinationClause (optional)
ENGINE, // EngineClause (optional)
SUBQUERY, // SelectUnionQuery
};
const bool attach, if_not_exists, populate;
};
}

View File

@ -0,0 +1,219 @@
#include <Parsers/New/AST/CreateTableQuery.h>
#include <IO/ReadHelpers.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/New/AST/EngineExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/AST/TableElementExpr.h>
#include <Parsers/New/AST/TableExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
// static
PtrTo<TableSchemaClause> TableSchemaClause::createDescription(PtrTo<TableElementList> list)
{
return PtrTo<TableSchemaClause>(new TableSchemaClause(ClauseType::DESCRIPTION, {list}));
}
// static
PtrTo<TableSchemaClause> TableSchemaClause::createAsTable(PtrTo<TableIdentifier> identifier)
{
return PtrTo<TableSchemaClause>(new TableSchemaClause(ClauseType::TABLE, {identifier}));
}
// static
PtrTo<TableSchemaClause> TableSchemaClause::createAsFunction(PtrTo<TableFunctionExpr> expr)
{
return PtrTo<TableSchemaClause>(new TableSchemaClause(ClauseType::FUNCTION, {expr}));
}
TableSchemaClause::TableSchemaClause(ClauseType type, PtrList exprs) : INode(exprs), clause_type(type)
{
}
ASTPtr TableSchemaClause::convertToOld() const
{
switch(clause_type)
{
case ClauseType::DESCRIPTION:
{
auto columns = std::make_shared<ASTColumns>();
auto column_list = std::make_shared<ASTExpressionList>();
auto constraint_list = std::make_shared<ASTExpressionList>();
auto index_list = std::make_shared<ASTExpressionList>();
for (const auto & element : get(ELEMENTS)->as<TableElementList &>())
{
switch(element->as<TableElementExpr>()->getType())
{
case TableElementExpr::ExprType::COLUMN:
column_list->children.push_back(element->convertToOld());
break;
case TableElementExpr::ExprType::CONSTRAINT:
constraint_list->children.push_back(element->convertToOld());
break;
case TableElementExpr::ExprType::INDEX:
index_list->children.push_back(element->convertToOld());
break;
}
}
if (!column_list->children.empty()) columns->set(columns->columns, column_list);
if (!constraint_list->children.empty()) columns->set(columns->constraints, constraint_list);
if (!index_list->children.empty()) columns->set(columns->indices, index_list);
return columns;
}
case ClauseType::FUNCTION:
case ClauseType::TABLE:
return get(EXPR)->convertToOld();
}
__builtin_unreachable(); // FIXME: old gcc compilers complain about reaching end of non-void function
}
String TableSchemaClause::dumpInfo() const
{
switch(clause_type)
{
case ClauseType::DESCRIPTION: return "Description";
case ClauseType::FUNCTION: return "Function";
case ClauseType::TABLE: return "Table";
}
__builtin_unreachable(); // FIXME: old gcc compilers complain about reaching end of non-void function
}
CreateTableQuery::CreateTableQuery(
PtrTo<ClusterClause> cluster,
bool attach_,
bool temporary_,
bool if_not_exists_,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<TableSchemaClause> schema,
PtrTo<EngineClause> engine,
PtrTo<SelectUnionQuery> query)
: DDLQuery(cluster, {identifier, uuid, schema, engine, query}), attach(attach_), temporary(temporary_), if_not_exists(if_not_exists_)
{
}
ASTPtr CreateTableQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
{
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid
= has(UUID) ? parseFromString<DB::UUID>(get(UUID)->convertToOld()->as<ASTLiteral>()->value.get<String>()) : table_id.uuid;
}
query->cluster = cluster_name;
query->attach = attach;
query->if_not_exists = if_not_exists;
query->temporary = temporary;
if (has(SCHEMA))
{
switch(get<TableSchemaClause>(SCHEMA)->getType())
{
case TableSchemaClause::ClauseType::DESCRIPTION:
{
query->set(query->columns_list, get(SCHEMA)->convertToOld());
break;
}
case TableSchemaClause::ClauseType::TABLE:
{
auto table_id = getTableIdentifier(get(SCHEMA)->convertToOld());
query->as_database = table_id.database_name;
query->as_table = table_id.table_name;
break;
}
case TableSchemaClause::ClauseType::FUNCTION:
{
query->as_table_function = get(SCHEMA)->convertToOld();
break;
}
}
}
if (has(ENGINE)) query->set(query->storage, get(ENGINE)->convertToOld());
if (has(SUBQUERY)) query->set(query->select, get(SUBQUERY)->convertToOld());
return query;
}
String CreateTableQuery::dumpInfo() const
{
String info;
if (attach) info += "attach=true, ";
else info += "attach=false, ";
if (temporary) info += "temporary=true, ";
else info += "temporary=false, ";
if (if_not_exists) info += "if_not_exists=true";
else info += "if_not_exists=false";
return info;
}
}
namespace DB
{
using namespace AST;
// TODO: assert(!(ctx->parent->TEMPORARY() ^ ctx->engineClause()))
antlrcpp::Any ParseTreeVisitor::visitClusterClause(ClickHouseParser::ClusterClauseContext *ctx)
{
auto literal = ctx->STRING_LITERAL() ? Literal::createString(ctx->STRING_LITERAL())
: Literal::createString(ctx->identifier()->getText());
return std::make_shared<ClusterClause>(literal);
}
antlrcpp::Any ParseTreeVisitor::visitCreateTableStmt(ClickHouseParser::CreateTableStmtContext *ctx)
{
auto uuid = ctx->uuidClause() ? visit(ctx->uuidClause()).as<PtrTo<UUIDClause>>() : nullptr;
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto schema = ctx->tableSchemaClause() ? visit(ctx->tableSchemaClause()).as<PtrTo<TableSchemaClause>>() : nullptr;
auto engine = ctx->engineClause() ? visit(ctx->engineClause()).as<PtrTo<EngineClause>>() : nullptr;
auto query = ctx->subqueryClause() ? visit(ctx->subqueryClause()).as<PtrTo<SelectUnionQuery>>() : nullptr;
return std::make_shared<CreateTableQuery>(
cluster, !!ctx->ATTACH(), !!ctx->TEMPORARY(), !!ctx->IF(), visit(ctx->tableIdentifier()), uuid, schema, engine, query);
}
antlrcpp::Any ParseTreeVisitor::visitSchemaDescriptionClause(ClickHouseParser::SchemaDescriptionClauseContext *ctx)
{
auto elems = std::make_shared<TableElementList>();
for (auto * elem : ctx->tableElementExpr()) elems->push(visit(elem));
return TableSchemaClause::createDescription(elems);
}
antlrcpp::Any ParseTreeVisitor::visitSchemaAsTableClause(ClickHouseParser::SchemaAsTableClauseContext *ctx)
{
return TableSchemaClause::createAsTable(visit(ctx->tableIdentifier()));
}
antlrcpp::Any ParseTreeVisitor::visitSchemaAsFunctionClause(ClickHouseParser::SchemaAsFunctionClauseContext *ctx)
{
return TableSchemaClause::createAsFunction(visit(ctx->tableFunctionExpr()));
}
antlrcpp::Any ParseTreeVisitor::visitSubqueryClause(ClickHouseParser::SubqueryClauseContext *ctx)
{
return visit(ctx->selectUnionStmt());
}
antlrcpp::Any ParseTreeVisitor::visitUuidClause(ClickHouseParser::UuidClauseContext *ctx)
{
return std::make_shared<UUIDClause>(Literal::createString(ctx->STRING_LITERAL()));
}
}

View File

@ -0,0 +1,76 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
#include "Parsers/New/AST/SelectUnionQuery.h"
namespace DB::AST
{
class TableSchemaClause : public INode
{
public:
static PtrTo<TableSchemaClause> createDescription(PtrTo<TableElementList> list);
static PtrTo<TableSchemaClause> createAsTable(PtrTo<TableIdentifier> identifier);
static PtrTo<TableSchemaClause> createAsFunction(PtrTo<TableFunctionExpr> expr);
enum class ClauseType
{
DESCRIPTION,
TABLE,
FUNCTION,
};
auto getType() const { return clause_type; }
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
// DESCRIPTION
ELEMENTS = 0, // TableElementList
// TABLE and FUNCTION
EXPR = 0, // TableIdentifier or TableFunctionExpr
};
ClauseType clause_type;
TableSchemaClause(ClauseType type, PtrList exprs);
String dumpInfo() const override;
};
class CreateTableQuery : public DDLQuery
{
public:
CreateTableQuery(
PtrTo<ClusterClause> cluster,
bool attach,
bool temporary,
bool if_not_exists,
PtrTo<TableIdentifier> identifier,
PtrTo<UUIDClause> uuid,
PtrTo<TableSchemaClause> schema,
PtrTo<EngineClause> engine,
PtrTo<SelectUnionQuery> query);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
UUID, // UUIDClause (optional)
SCHEMA, // TableSchemaClause
ENGINE, // EngineClause
SUBQUERY, // SelectUnionQuery
};
const bool attach, temporary, if_not_exists;
String dumpInfo() const override;
};
}

View File

@ -0,0 +1,62 @@
#include <Parsers/New/AST/CreateViewQuery.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/New/AST/CreateTableQuery.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
CreateViewQuery::CreateViewQuery(
PtrTo<ClusterClause> cluster,
bool attach_,
bool replace_,
bool if_not_exists_,
PtrTo<TableIdentifier> identifier,
PtrTo<TableSchemaClause> clause,
PtrTo<SelectUnionQuery> query)
: DDLQuery(cluster, {identifier, clause, query}), attach(attach_), replace(replace_), if_not_exists(if_not_exists_)
{
}
ASTPtr CreateViewQuery::convertToOld() const
{
auto query = std::make_shared<ASTCreateQuery>();
{
auto table_id = getTableIdentifier(get(NAME)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid = table_id.uuid;
}
query->attach = attach;
query->replace_view = replace;
query->if_not_exists = if_not_exists;
query->is_view = true;
query->cluster = cluster_name;
if (has(SCHEMA)) query->set(query->columns_list, get(SCHEMA)->convertToOld());
query->set(query->select, get(SUBQUERY)->convertToOld());
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitCreateViewStmt(ClickHouseParser::CreateViewStmtContext *ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto schema = ctx->tableSchemaClause() ? visit(ctx->tableSchemaClause()).as<PtrTo<TableSchemaClause>>() : nullptr;
return std::make_shared<CreateViewQuery>(
cluster, !!ctx->ATTACH(), !!ctx->REPLACE(), !!ctx->IF(), visit(ctx->tableIdentifier()), schema, visit(ctx->subqueryClause()));
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class CreateViewQuery : public DDLQuery
{
public:
CreateViewQuery(
PtrTo<ClusterClause> cluster,
bool attach,
bool replace,
bool if_not_exists,
PtrTo<TableIdentifier> identifier,
PtrTo<TableSchemaClause> clause,
PtrTo<SelectUnionQuery> query);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // TableIdentifier
SCHEMA = 1, // TableSchemaClause (optional)
SUBQUERY = 2, // SelectUnionQuery
};
const bool attach, replace, if_not_exists;
};
}

View File

@ -0,0 +1,6 @@
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <Parsers/New/AST/Query.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTQueryWithOnCluster.h>
#include <Parsers/New/AST/Identifier.h>
namespace DB::AST
{
class DDLQuery : public Query
{
protected:
DDLQuery(PtrTo<ClusterClause> cluster, std::initializer_list<Ptr> list)
: Query(list), cluster_name(cluster ? cluster->convertToOld()->as<ASTLiteral>()->value.get<String>() : String{})
{
}
DDLQuery(PtrTo<ClusterClause> cluster, PtrList list)
: Query(list), cluster_name(cluster ? cluster->convertToOld()->as<ASTLiteral>()->value.get<String>() : String{})
{
}
const String cluster_name;
};
}

View File

@ -0,0 +1,36 @@
#include <Parsers/New/AST/DescribeQuery.h>
#include <Parsers/TablePropertiesQueriesASTs.h>
#include <Parsers/New/AST/TableExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
DescribeQuery::DescribeQuery(PtrTo<TableExpr> expr) : Query{expr}
{
}
ASTPtr DescribeQuery::convertToOld() const
{
auto query = std::make_shared<ASTDescribeQuery>();
query->table_expression = get(EXPR)->convertToOld();
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitDescribeStmt(ClickHouseParser::DescribeStmtContext *ctx)
{
return std::make_shared<DescribeQuery>(visit(ctx->tableExpr()).as<PtrTo<TableExpr>>());
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <Parsers/New/AST/Query.h>
namespace DB::AST
{
// TODO: rewrite to
// `SELECT name, type, default_type, default_expression, comment, codec_expression, ttl_expression FROM system.columns
// WHERE database=db AND table=table`
class DescribeQuery : public Query
{
public:
explicit DescribeQuery(PtrTo<TableExpr> expr);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
EXPR = 0,
};
};
}

View File

@ -0,0 +1,106 @@
#include <Parsers/New/AST/DropQuery.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/ParseTreeVisitor.h>
#include <Parsers/ASTDropQuery.h>
namespace DB::AST
{
// static
PtrTo<DropQuery>
DropQuery::createDropDatabase(bool detach, bool if_exists, PtrTo<DatabaseIdentifier> identifier, PtrTo<ClusterClause> cluster)
{
auto query = PtrTo<DropQuery>(new DropQuery(cluster, QueryType::DATABASE, {identifier}));
query->detach = detach;
query->if_exists = if_exists;
return query;
}
// static
PtrTo<DropQuery>
DropQuery::createDropDictionary(bool detach, bool if_exists, PtrTo<TableIdentifier> identifier, PtrTo<ClusterClause> cluster)
{
auto query = PtrTo<DropQuery>(new DropQuery(cluster, QueryType::DICTIONARY, {identifier}));
query->detach = detach;
query->if_exists = if_exists;
return query;
}
// static
PtrTo<DropQuery>
DropQuery::createDropTable(bool detach, bool if_exists, bool temporary, PtrTo<TableIdentifier> identifier, PtrTo<ClusterClause> cluster)
{
auto query = PtrTo<DropQuery>(new DropQuery(cluster, QueryType::TABLE, {identifier}));
query->detach = detach;
query->if_exists = if_exists;
query->temporary = temporary;
return query;
}
DropQuery::DropQuery(PtrTo<ClusterClause> cluster, QueryType type, PtrList exprs) : DDLQuery(cluster, exprs), query_type(type)
{
}
ASTPtr DropQuery::convertToOld() const
{
auto query = std::make_shared<ASTDropQuery>();
query->kind = detach ? ASTDropQuery::Detach : ASTDropQuery::Drop;
query->if_exists = if_exists;
query->temporary = temporary;
query->cluster = cluster_name;
// TODO: refactor |ASTQueryWithTableAndOutput| to accept |ASTIdentifier|
switch(query_type)
{
case QueryType::DATABASE:
query->database = get<DatabaseIdentifier>(NAME)->getName();
break;
case QueryType::DICTIONARY:
query->is_dictionary = true;
query->table = get<TableIdentifier>(NAME)->getName();
if (auto database = get<TableIdentifier>(NAME)->getDatabase())
query->database = database->getName();
break;
case QueryType::TABLE:
{
query->table = get<TableIdentifier>(NAME)->getName();
if (auto database = get<TableIdentifier>(NAME)->getDatabase())
query->database = database->getName();
break;
}
}
convertToOldPartially(query);
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitDropDatabaseStmt(ClickHouseParser::DropDatabaseStmtContext *ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
return DropQuery::createDropDatabase(!!ctx->DETACH(), !!ctx->EXISTS(), visit(ctx->databaseIdentifier()), cluster);
}
antlrcpp::Any ParseTreeVisitor::visitDropTableStmt(ClickHouseParser::DropTableStmtContext *ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
if (ctx->TABLE())
return DropQuery::createDropTable(!!ctx->DETACH(), !!ctx->EXISTS(), !!ctx->TEMPORARY(), visit(ctx->tableIdentifier()), cluster);
if (ctx->DICTIONARY())
return DropQuery::createDropDictionary(!!ctx->DETACH(), !!ctx->EXISTS(), visit(ctx->tableIdentifier()), cluster);
__builtin_unreachable();
}
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class DropQuery : public DDLQuery
{
public:
static PtrTo<DropQuery>
createDropDatabase(bool detach, bool if_exists, PtrTo<DatabaseIdentifier> identifier, PtrTo<ClusterClause> cluster);
static PtrTo<DropQuery>
createDropTable(bool detach, bool if_exists, bool temporary, PtrTo<TableIdentifier> identifier, PtrTo<ClusterClause> cluster);
static PtrTo<DropQuery>
createDropDictionary(bool detach, bool if_exists, PtrTo<TableIdentifier> identifier, PtrTo<ClusterClause> cluster);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0,
};
enum class QueryType
{
DATABASE,
DICTIONARY,
TABLE,
};
const QueryType query_type;
bool detach = false;
bool if_exists = false;
bool temporary = false;
DropQuery(PtrTo<ClusterClause> cluster, QueryType type, PtrList exprs);
};
}

View File

@ -0,0 +1,199 @@
#include <Parsers/New/AST/EngineExpr.h>
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTTTLElement.h>
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/ParseTreeVisitor.h>
#include <Storages/DataDestinationType.h>
#include <Storages/TTLMode.h>
namespace DB::ErrorCodes
{
extern const int UNEXPECTED_AST_STRUCTURE;
}
namespace DB::AST
{
EngineClause::EngineClause(PtrTo<EngineExpr> expr) : INode(MAX_INDEX)
{
set(ENGINE, expr);
}
void EngineClause::setOrderByClause(PtrTo<OrderByClause> clause)
{
set(ORDER_BY, clause);
}
void EngineClause::setPartitionByClause(PtrTo<PartitionByClause> clause)
{
set(PARTITION_BY, clause);
}
void EngineClause::setPrimaryKeyClause(PtrTo<PrimaryKeyClause> clause)
{
set(PRIMARY_KEY, clause);
}
void EngineClause::setSampleByClause(PtrTo<SampleByClause> clause)
{
set(SAMPLE_BY, clause);
}
void EngineClause::setTTLClause(PtrTo<TTLClause> clause)
{
set(TTL, clause);
}
void EngineClause::setSettingsClause(PtrTo<SettingsClause> clause)
{
set(SETTINGS, clause);
}
ASTPtr EngineClause::convertToOld() const
{
auto storage = std::make_shared<ASTStorage>();
storage->set(storage->engine, get(ENGINE)->convertToOld());
if (has(PARTITION_BY)) storage->set(storage->partition_by, get(PARTITION_BY)->convertToOld());
if (has(PRIMARY_KEY)) storage->set(storage->primary_key, get(PRIMARY_KEY)->convertToOld());
if (has(ORDER_BY))
{
/// XXX: old parser used very strange grammar for this case, instead of using OrderByElement's.
auto expr_list = get(ORDER_BY)->convertToOld();
if (expr_list->children.size() > 1)
throw DB::Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, "Cannot convert multiple ORDER expression to old AST");
storage->set(storage->order_by, expr_list->children[0]->children[0]);
}
if (has(SAMPLE_BY)) storage->set(storage->sample_by, get(SAMPLE_BY)->convertToOld());
if (has(TTL)) storage->set(storage->ttl_table, get(TTL)->convertToOld());
if (has(SETTINGS))
{
storage->set(storage->settings, get(SETTINGS)->convertToOld());
storage->settings->is_standalone = false;
}
return storage;
}
EngineExpr::EngineExpr(PtrTo<Identifier> identifier, PtrTo<ColumnExprList> args) : INode{identifier, args}
{
}
ASTPtr EngineExpr::convertToOld() const
{
auto expr = std::make_shared<ASTFunction>();
expr->name = get<Identifier>(NAME)->getName();
expr->no_empty_args = true;
if (has(ARGS))
{
expr->arguments = get(ARGS)->convertToOld();
expr->children.push_back(expr->arguments);
}
return expr;
}
TTLExpr::TTLExpr(PtrTo<ColumnExpr> expr, TTLType type, PtrTo<StringLiteral> literal) : INode{expr, literal}, ttl_type(type)
{
}
ASTPtr TTLExpr::convertToOld() const
{
TTLMode mode = TTLMode::DELETE;
DataDestinationType destination_type = DataDestinationType::DELETE;
String destination_name;
switch(ttl_type)
{
case TTLType::DELETE:
mode = TTLMode::DELETE;
destination_type = DataDestinationType::DELETE;
break;
case TTLType::TO_DISK:
mode = TTLMode::MOVE;
destination_type = DataDestinationType::DISK;
destination_name = get(TYPE)->convertToOld()->as<ASTLiteral>()->value.get<String>();
break;
case TTLType::TO_VOLUME:
mode = TTLMode::MOVE;
destination_type = DataDestinationType::VOLUME;
destination_name = get(TYPE)->convertToOld()->as<ASTLiteral>()->value.get<String>();
break;
}
auto expr = std::make_shared<ASTTTLElement>(mode, destination_type, destination_name);
expr->setTTL(get(EXPR)->convertToOld());
return expr;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitEngineClause(ClickHouseParser::EngineClauseContext *ctx)
{
auto clause = std::make_shared<EngineClause>(visit(ctx->engineExpr()).as<PtrTo<EngineExpr>>());
if (!ctx->orderByClause().empty()) clause->setOrderByClause(visit(ctx->orderByClause(0)));
if (!ctx->partitionByClause().empty()) clause->setPartitionByClause(visit(ctx->partitionByClause(0)));
if (!ctx->primaryKeyClause().empty()) clause->setPrimaryKeyClause(visit(ctx->primaryKeyClause(0)));
if (!ctx->sampleByClause().empty()) clause->setSampleByClause(visit(ctx->sampleByClause(0)));
if (!ctx->ttlClause().empty()) clause->setTTLClause(visit(ctx->ttlClause(0)));
if (!ctx->settingsClause().empty()) clause->setSettingsClause(visit(ctx->settingsClause(0)));
return clause;
}
antlrcpp::Any ParseTreeVisitor::visitEngineExpr(ClickHouseParser::EngineExprContext *ctx)
{
auto list = ctx->columnExprList() ? visit(ctx->columnExprList()).as<PtrTo<ColumnExprList>>() : nullptr;
return std::make_shared<EngineExpr>(visit(ctx->identifierOrNull()), list);
}
antlrcpp::Any ParseTreeVisitor::visitPartitionByClause(ClickHouseParser::PartitionByClauseContext *ctx)
{
return std::make_shared<PartitionByClause>(visit(ctx->columnExpr()).as<PtrTo<ColumnExpr>>());
}
antlrcpp::Any ParseTreeVisitor::visitPrimaryKeyClause(ClickHouseParser::PrimaryKeyClauseContext *ctx)
{
return std::make_shared<PrimaryKeyClause>(visit(ctx->columnExpr()).as<PtrTo<ColumnExpr>>());
}
antlrcpp::Any ParseTreeVisitor::visitSampleByClause(ClickHouseParser::SampleByClauseContext *ctx)
{
return std::make_shared<SampleByClause>(visit(ctx->columnExpr()).as<PtrTo<ColumnExpr>>());
}
antlrcpp::Any ParseTreeVisitor::visitTtlClause(ClickHouseParser::TtlClauseContext *ctx)
{
auto list = std::make_shared<TTLExprList>();
for (auto * expr : ctx->ttlExpr()) list->push(visit(expr));
return std::make_shared<TTLClause>(list);
}
antlrcpp::Any ParseTreeVisitor::visitTtlExpr(ClickHouseParser::TtlExprContext *ctx)
{
TTLExpr::TTLType type;
PtrTo<StringLiteral> literal;
if (ctx->DISK()) type = TTLExpr::TTLType::TO_DISK;
else if (ctx->VOLUME()) type = TTLExpr::TTLType::TO_VOLUME;
else type = TTLExpr::TTLType::DELETE;
if (ctx->STRING_LITERAL()) literal = Literal::createString(ctx->STRING_LITERAL());
return std::make_shared<TTLExpr>(visit(ctx->columnExpr()), type, literal);
}
}

View File

@ -0,0 +1,85 @@
#pragma once
#include <Parsers/New/AST/INode.h>
namespace DB::AST
{
// Clauses
using PartitionByClause = SimpleClause<ColumnExpr>;
using SampleByClause = SimpleClause<ColumnExpr>;
class EngineClause : public INode
{
public:
explicit EngineClause(PtrTo<EngineExpr> expr);
void setOrderByClause(PtrTo<OrderByClause> clause);
void setPartitionByClause(PtrTo<PartitionByClause> clause);
void setPrimaryKeyClause(PtrTo<PrimaryKeyClause> clause);
void setSampleByClause(PtrTo<SampleByClause> clause);
void setTTLClause(PtrTo<TTLClause> clause);
void setSettingsClause(PtrTo<SettingsClause> clause);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
ENGINE = 0, // EngineExpr
ORDER_BY, // OrderByClause (optional)
PARTITION_BY, // PartitionByClause (optional)
PRIMARY_KEY, // PrimaryKeyClause (optional)
SAMPLE_BY, // SampleByClause (optional)
TTL, // TTLClause (optional)
SETTINGS, // SettingsClause (optional)
MAX_INDEX,
};
};
// Expressions
class EngineExpr : public INode
{
public:
EngineExpr(PtrTo<Identifier> identifier, PtrTo<ColumnExprList> args);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
NAME = 0, // Identifier
ARGS, // ColumnExprList (optional)
};
};
class TTLExpr : public INode
{
public:
enum class TTLType
{
DELETE,
TO_DISK,
TO_VOLUME,
};
TTLExpr(PtrTo<ColumnExpr> expr, TTLType type, PtrTo<StringLiteral> literal);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
EXPR = 0, // ColumnExpr
TYPE = 1, // StringLiteral (optional)
};
TTLType ttl_type;
};
}

View File

@ -0,0 +1,55 @@
#include <Parsers/New/AST/ExistsQuery.h>
#include <Interpreters/StorageID.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/ParseTreeVisitor.h>
#include <Parsers/TablePropertiesQueriesASTs.h>
namespace DB::AST
{
ExistsQuery::ExistsQuery(QueryType type, bool temporary_, PtrTo<TableIdentifier> identifier)
: Query{identifier}, query_type(type), temporary(temporary_)
{
}
ASTPtr ExistsQuery::convertToOld() const
{
std::shared_ptr<ASTQueryWithTableAndOutput> query;
switch(query_type)
{
case QueryType::DICTIONARY:
query = std::make_shared<ASTExistsDictionaryQuery>();
break;
case QueryType::TABLE:
query = std::make_shared<ASTExistsTableQuery>();
query->temporary = temporary;
break;
}
// FIXME: this won't work if table doesn't exist
auto table_id = getTableIdentifier(get(TABLE)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid = table_id.uuid;
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitExistsStmt(ClickHouseParser::ExistsStmtContext *ctx)
{
auto type = ctx->TABLE() ? ExistsQuery::QueryType::TABLE : ExistsQuery::QueryType::DICTIONARY;
return std::make_shared<ExistsQuery>(type, !!ctx->TEMPORARY(), visit(ctx->tableIdentifier()));
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <Parsers/New/AST/Query.h>
namespace DB::AST
{
class ExistsQuery : public Query
{
public:
enum class QueryType
{
DICTIONARY,
TABLE,
};
ExistsQuery(QueryType type, bool temporary, PtrTo<TableIdentifier> identifier);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
TABLE = 0, // TableIdentifier
};
const QueryType query_type;
const bool temporary;
};
}

View File

@ -0,0 +1,35 @@
#include <Parsers/New/AST/ExplainQuery.h>
#include <Parsers/ASTExplainQuery.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
ExplainQuery::ExplainQuery(PtrTo<Query> query) : Query{query}
{
}
ASTPtr ExplainQuery::convertToOld() const
{
auto query = std::make_shared<ASTExplainQuery>(ASTExplainQuery::AnalyzedSyntax);
query->setExplainedQuery(get(QUERY)->convertToOld());
return query;
}
}
namespace DB
{
using namespace DB::AST;
antlrcpp::Any ParseTreeVisitor::visitExplainStmt(ClickHouseParser::ExplainStmtContext *ctx)
{
return std::make_shared<ExplainQuery>(visit(ctx->query()).as<PtrTo<Query>>());
}
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <Parsers/New/AST/Query.h>
namespace DB::AST
{
class ExplainQuery : public Query
{
public:
explicit ExplainQuery(PtrTo<Query> query);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
QUERY = 0, // Query
};
};
}

103
src/Parsers/New/AST/INode.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
#include <Parsers/New/AST/fwd_decl.h>
#include <common/demangle.h>
#include <Common/TypePromotion.h>
#include <Parsers/ASTExpressionList.h>
#include <initializer_list>
#include <iostream>
namespace DB::AST
{
class INode : public TypePromotion<INode>
{
public:
virtual ~INode() = default;
virtual ASTPtr convertToOld() const { return ASTPtr(); }
virtual String toString() const { return {}; }
void dump() const { dump(0); }
protected:
INode() = default;
INode(std::initializer_list<Ptr> list) { children = list; }
explicit INode(PtrList list) { children = list; }
explicit INode(size_t size) { children.resize(size); }
void push(const Ptr& child) { children.push_back(child); }
void set(size_t i, const Ptr& child) { children[i] = child; }
bool has(size_t i) const { return i < children.size() && children[i]; }
const Ptr & get(size_t i) const { return children[i]; }
template <class ChildType>
bool has(size_t i) const { return has(i) && children[i]->as<ChildType>(); }
template <class ChildType>
ChildType * get(size_t i) const { return children[i]->template as<ChildType>(); }
auto begin() const { return children.cbegin(); }
auto end() const { return children.cend(); }
auto size() const { return children.size(); }
private:
PtrList children; // any child potentially may point to |nullptr|
void dump(int indentation) const
{
for (auto i = 0; i < indentation; ++i) std::cout << " ";
std::cout << "" << demangle(typeid(*this).name()) << " (" << dumpInfo() << ")" << std::endl;
for (const auto & child : children) if (child) child->dump(indentation + 1);
}
virtual String dumpInfo() const { return ""; }
};
template <class T, char Separator>
class List : public INode {
public:
List() = default;
List(std::initializer_list<PtrTo<T>> list)
{
for (const auto & i : list) push(i);
}
using INode::begin;
using INode::end;
using INode::size;
void push(const PtrTo<T> & node) { INode::push(node); }
ASTPtr convertToOld() const override
{
auto list = std::make_shared<ASTExpressionList>(Separator);
for (const auto & child : *this) list->children.emplace_back(child->convertToOld());
return list;
}
String toString() const override
{
if (!size()) return {};
auto string = (*begin())->toString();
for (auto next = ++begin(); next != end(); ++next)
string += String(1, Separator) + " " + (*next)->toString();
return string;
}
};
template <class T>
class SimpleClause : public INode
{
public:
explicit SimpleClause(PtrTo<T> expr) : INode{expr} {}
ASTPtr convertToOld() const override { return get(0)->convertToOld(); }
};
}

View File

@ -0,0 +1,175 @@
#include <Parsers/New/AST/Identifier.h>
#include <IO/ReadHelpers.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
Identifier::Identifier(const String & name_) : name(name_)
{
if (name.front() == '`' || name.front() == '"')
{
String s;
ReadBufferFromMemory in(name.data(), name.size());
if (name.front() == '`')
readBackQuotedStringWithSQLStyle(s, in);
else
readDoubleQuotedStringWithSQLStyle(s, in);
assert(in.count() == name.size());
name = s;
}
}
Identifier::Identifier(const String & name_, const String & nested_name) : name(name_ + "." + nested_name)
{
}
ASTPtr Identifier::convertToOld() const
{
return std::make_shared<ASTIdentifier>(getQualifiedName());
}
String Identifier::toString() const
{
return getQualifiedName();
}
DatabaseIdentifier::DatabaseIdentifier(PtrTo<Identifier> name) : Identifier(*name)
{
}
TableIdentifier::TableIdentifier(PtrTo<DatabaseIdentifier> database, PtrTo<Identifier> name) : Identifier(*name), db(database)
{
}
void TableIdentifier::makeCompound() const
{
if (db)
{
name = db->getName();
db.reset();
}
}
ASTPtr TableIdentifier::convertToOld() const
{
std::vector<String> parts;
if (db && !db->getName().empty()) parts.push_back(db->getName());
parts.push_back(getName());
return std::make_shared<ASTIdentifier>(std::move(parts));
}
ColumnIdentifier::ColumnIdentifier(PtrTo<TableIdentifier> table_, PtrTo<Identifier> name) : Identifier(name->getName()), table(table_)
{
}
void ColumnIdentifier::makeCompound() const
{
if (table)
{
name = table->getName() + "." + getName();
if (table->getDatabase()) table->makeCompound();
else table.reset();
}
}
ASTPtr ColumnIdentifier::convertToOld() const
{
std::vector<String> parts;
if (table)
{
if (table->getDatabase()) parts.push_back(table->getDatabase()->getName());
parts.push_back(table->getName());
}
parts.push_back(getName());
return std::make_shared<ASTIdentifier>(std::move(parts));
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitAlias(ClickHouseParser::AliasContext *ctx)
{
if (ctx->IDENTIFIER()) return std::make_shared<Identifier>(ctx->IDENTIFIER()->getText());
if (ctx->keywordForAlias()) return std::make_shared<Identifier>(ctx->keywordForAlias()->getText());
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitColumnIdentifier(ClickHouseParser::ColumnIdentifierContext *ctx)
{
auto table = ctx->tableIdentifier() ? visit(ctx->tableIdentifier()).as<PtrTo<TableIdentifier>>() : nullptr;
return std::make_shared<ColumnIdentifier>(table, visit(ctx->nestedIdentifier()));
}
antlrcpp::Any ParseTreeVisitor::visitDatabaseIdentifier(ClickHouseParser::DatabaseIdentifierContext *ctx)
{
return std::make_shared<DatabaseIdentifier>(visit(ctx->identifier()).as<PtrTo<Identifier>>());
}
antlrcpp::Any ParseTreeVisitor::visitIdentifier(ClickHouseParser::IdentifierContext *ctx)
{
if (ctx->IDENTIFIER()) return std::make_shared<Identifier>(ctx->IDENTIFIER()->getText());
if (ctx->interval()) return std::make_shared<Identifier>(ctx->interval()->getText());
if (ctx->keyword()) return std::make_shared<Identifier>(ctx->keyword()->getText());
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitIdentifierOrNull(ClickHouseParser::IdentifierOrNullContext *ctx)
{
if (ctx->identifier()) return visit(ctx->identifier());
if (ctx->NULL_SQL())
{
if (ctx->NULL_SQL()->getSymbol()->getText() == "Null") return std::make_shared<Identifier>("Null");
else {
// TODO: raise error
}
}
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitInterval(ClickHouseParser::IntervalContext *)
{
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitKeyword(ClickHouseParser::KeywordContext *)
{
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitKeywordForAlias(ClickHouseParser::KeywordForAliasContext *)
{
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitNestedIdentifier(ClickHouseParser::NestedIdentifierContext *ctx)
{
if (ctx->identifier().size() == 2)
{
auto name1 = visit(ctx->identifier(0)).as<PtrTo<Identifier>>()->getName();
auto name2 = visit(ctx->identifier(1)).as<PtrTo<Identifier>>()->getName();
return std::make_shared<Identifier>(name1, name2);
}
else return visit(ctx->identifier(0));
}
antlrcpp::Any ParseTreeVisitor::visitTableIdentifier(ClickHouseParser::TableIdentifierContext *ctx)
{
auto database = ctx->databaseIdentifier() ? visit(ctx->databaseIdentifier()).as<PtrTo<DatabaseIdentifier>>() : nullptr;
return std::make_shared<TableIdentifier>(database, visit(ctx->identifier()));
}
}

View File

@ -0,0 +1,66 @@
#pragma once
#include <Parsers/New/AST/INode.h>
namespace DB::AST
{
class Identifier : public INode
{
public:
explicit Identifier(const String & name_);
Identifier(const String & name_, const String & nested_name);
const auto & getName() const { return name; }
ASTPtr convertToOld() const override;
String toString() const override;
virtual String getQualifiedName() const { return name; };
protected:
mutable String name; // protected and non-const because identifiers may become `column.nested` from `table.column`
String dumpInfo() const override { return getQualifiedName(); }
};
class DatabaseIdentifier : public Identifier
{
public:
explicit DatabaseIdentifier(PtrTo<Identifier> name);
};
class TableIdentifier : public Identifier
{
public:
TableIdentifier(PtrTo<DatabaseIdentifier> database, PtrTo<Identifier> name);
auto getDatabase() const { return db; }
void makeCompound() const;
String getQualifiedName() const override { return (db ? db->getQualifiedName() + "." : String()) + getName(); }
ASTPtr convertToOld() const override;
private:
mutable PtrTo<DatabaseIdentifier> db;
};
class ColumnIdentifier : public Identifier
{
public:
ColumnIdentifier(PtrTo<TableIdentifier> table, PtrTo<Identifier> name);
auto getTable() const { return table; }
void makeCompound() const;
String getQualifiedName() const override { return (table ? table->getQualifiedName() + "." : String()) + getName(); }
ASTPtr convertToOld() const override;
private:
mutable PtrTo<TableIdentifier> table;
};
}

View File

@ -0,0 +1,125 @@
#include <Parsers/New/AST/InsertQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTInsertQuery.h>
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/SelectUnionQuery.h>
#include <Parsers/New/AST/TableExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
// static
PtrTo<DataClause> DataClause::createFormat(PtrTo<Identifier> identifier, size_t data_offset)
{
PtrTo<DataClause> clause(new DataClause(ClauseType::FORMAT, {identifier}));
clause->offset = data_offset;
return clause;
}
// static
PtrTo<DataClause> DataClause::createSelect(PtrTo<SelectUnionQuery> query)
{
return PtrTo<DataClause>(new DataClause(ClauseType::SELECT, {query}));
}
// static
PtrTo<DataClause> DataClause::createValues(size_t data_offset)
{
PtrTo<DataClause> clause(new DataClause(ClauseType::VALUES, {}));
clause->offset = data_offset;
return clause;
}
DataClause::DataClause(ClauseType type, PtrList exprs) : INode(exprs), clause_type(type)
{
}
ASTPtr DataClause::convertToOld() const
{
if (clause_type != ClauseType::SELECT) return {};
return get(SUBQUERY)->convertToOld();
}
// static
PtrTo<InsertQuery> InsertQuery::createTable(PtrTo<TableIdentifier> identifier, PtrTo<ColumnNameList> list, PtrTo<DataClause> clause)
{
return PtrTo<InsertQuery>(new InsertQuery(QueryType::TABLE, {identifier, list, clause}));
}
// static
PtrTo<InsertQuery> InsertQuery::createFunction(PtrTo<TableFunctionExpr> function, PtrTo<ColumnNameList> list, PtrTo<DataClause> clause)
{
return PtrTo<InsertQuery>(new InsertQuery(QueryType::FUNCTION, {function, list, clause}));
}
InsertQuery::InsertQuery(QueryType type, PtrList exprs) : Query(exprs), query_type(type)
{
}
ASTPtr InsertQuery::convertToOld() const
{
auto query = std::make_shared<ASTInsertQuery>();
switch(query_type)
{
case QueryType::FUNCTION:
query->table_function = get(FUNCTION)->convertToOld();
break;
case QueryType::TABLE:
query->table_id = getTableIdentifier(get(IDENTIFIER)->convertToOld());
break;
}
if (has(COLUMNS)) query->columns = get(COLUMNS)->convertToOld();
if (get<DataClause>(DATA)->getType() == DataClause::ClauseType::SELECT)
{
query->select = get(DATA)->convertToOld();
query->children.push_back(query->select);
}
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitColumnsClause(ClickHouseParser::ColumnsClauseContext *ctx)
{
auto list = std::make_shared<ColumnNameList>();
for (auto * name : ctx->nestedIdentifier()) list->push(visit(name));
return list;
}
antlrcpp::Any ParseTreeVisitor::visitDataClauseFormat(ClickHouseParser::DataClauseFormatContext *ctx)
{
return DataClause::createFormat(visit(ctx->identifier()), ctx->getStop()->getStopIndex() + 1);
}
antlrcpp::Any ParseTreeVisitor::visitDataClauseSelect(ClickHouseParser::DataClauseSelectContext *ctx)
{
return DataClause::createSelect(visit(ctx->selectUnionStmt()));
}
antlrcpp::Any ParseTreeVisitor::visitDataClauseValues(ClickHouseParser::DataClauseValuesContext *ctx)
{
return DataClause::createValues(ctx->getStop()->getStopIndex() + 1);
}
antlrcpp::Any ParseTreeVisitor::visitInsertStmt(ClickHouseParser::InsertStmtContext *ctx)
{
auto columns = ctx->columnsClause() ? visit(ctx->columnsClause()).as<PtrTo<ColumnNameList>>() : nullptr;
if (ctx->FUNCTION()) return InsertQuery::createFunction(visit(ctx->tableFunctionExpr()), columns, visit(ctx->dataClause()));
if (ctx->tableIdentifier()) return InsertQuery::createTable(visit(ctx->tableIdentifier()), columns, visit(ctx->dataClause()));
__builtin_unreachable();
}
}

View File

@ -0,0 +1,73 @@
#pragma once
#include <Parsers/New/AST/Query.h>
namespace DB::AST
{
class DataClause : public INode
{
public:
enum class ClauseType
{
FORMAT,
SELECT,
VALUES,
};
static PtrTo<DataClause> createFormat(PtrTo<Identifier> identifier, size_t data_offset);
static PtrTo<DataClause> createSelect(PtrTo<SelectUnionQuery> query);
static PtrTo<DataClause> createValues(size_t data_offset);
auto getType() const { return clause_type; }
auto getOffset() const { return offset; }
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
FORMAT = 0, // Identifier
SUBQUERY = 0, // SelectUnionQuery
};
ClauseType clause_type;
size_t offset = 0;
DataClause(ClauseType type, PtrList exprs);
};
class InsertQuery : public Query
{
public:
static PtrTo<InsertQuery> createFunction(PtrTo<TableFunctionExpr> function, PtrTo<ColumnNameList> list, PtrTo<DataClause> clause);
static PtrTo<InsertQuery> createTable(PtrTo<TableIdentifier> identifier, PtrTo<ColumnNameList> list, PtrTo<DataClause> clause);
bool hasData() const { return get<DataClause>(DATA)->getType() != DataClause::ClauseType::SELECT; }
size_t getDataOffset() const { return get<DataClause>(DATA)->getOffset(); }
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
IDENTIFIER = 0, // TableIdentifier
FUNCTION = 0, // TableFunctionExpr
COLUMNS = 1, // ColumnNameList
DATA = 2, // DataClause
};
enum class QueryType
{
FUNCTION,
TABLE,
};
QueryType query_type;
InsertQuery(QueryType type, PtrList exprs);
String dumpInfo() const override { return String("has_data=") + (hasData() ? "true" : "false"); }
};
}

View File

@ -0,0 +1,326 @@
#include <Parsers/New/AST/JoinExpr.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Parsers/New/AST/RatioExpr.h>
#include <Parsers/New/AST/TableExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::ErrorCodes
{
extern const int UNEXPECTED_AST_STRUCTURE;
}
namespace DB::AST
{
JoinConstraintClause::JoinConstraintClause(ConstraintType type_, PtrTo<ColumnExprList> list) : SimpleClause{list}, type(type_)
{
}
SampleClause::SampleClause(PtrTo<RatioExpr> ratio, PtrTo<RatioExpr> offset) : INode{ratio, offset}
{
}
ASTPtr SampleClause::convertToOld() const
{
auto list = std::make_shared<ASTExpressionList>();
list->children.push_back(get(RATIO)->convertToOld());
if (has(OFFSET)) list->children.push_back(get(OFFSET)->convertToOld());
return list;
}
// static
PtrTo<JoinExpr> JoinExpr::createTableExpr(PtrTo<TableExpr> expr, PtrTo<SampleClause> clause, bool final)
{
return PtrTo<JoinExpr>(new JoinExpr(JoinExpr::ExprType::TABLE, final, {expr, clause}));
}
// static
PtrTo<JoinExpr> JoinExpr::createJoinOp(
PtrTo<JoinExpr> left_expr, PtrTo<JoinExpr> right_expr, JoinOpType op, JoinOpMode mode, PtrTo<JoinConstraintClause> clause)
{
return PtrTo<JoinExpr>(new JoinExpr(ExprType::JOIN_OP, op, mode, {left_expr, right_expr, clause}));
}
JoinExpr::JoinExpr(JoinExpr::ExprType type, bool final_, PtrList exprs) : INode(exprs), expr_type(type), final(final_)
{
}
JoinExpr::JoinExpr(JoinExpr::ExprType type, JoinExpr::JoinOpType op, JoinExpr::JoinOpMode mode, PtrList exprs)
: INode(exprs), expr_type(type), op_type(op), op_mode(mode)
{
}
ASTPtr JoinExpr::convertToOld() const
{
/** The sole convertable chain of Join's may look like:
*
* FROM table1 JOIN table2 ON SMTH JOIN table3 ON SMTH JOIN
*
* Since Join is a left-associative operation then the tree will look like:
*
* JoinExpr
* / \
* JoinExpr
* / \
* JoinExpr table3
* / \
* table1 table2
*
* To linearize this tree we have to start from the top-most expression.
*/
auto list = std::make_shared<ASTExpressionList>();
if (expr_type == ExprType::TABLE)
{
auto element = std::make_shared<ASTTablesInSelectQueryElement>();
element->children.emplace_back(get(TABLE)->convertToOld());
element->table_expression = element->children.back();
element->table_expression->as<ASTTableExpression>()->final = final;
if (has(SAMPLE))
{
auto old_list = get(SAMPLE)->convertToOld();
element->table_expression->as<ASTTableExpression>()->sample_size = old_list->children[0];
element->table_expression->children.push_back(element->table_expression->as<ASTTableExpression>()->sample_size);
if (old_list->children.size() > 1)
{
element->table_expression->as<ASTTableExpression>()->sample_offset = old_list->children[1];
element->table_expression->children.push_back(element->table_expression->as<ASTTableExpression>()->sample_offset);
}
}
list->children.emplace_back(element);
}
else if (expr_type == ExprType::JOIN_OP)
{
if (get<JoinExpr>(RIGHT_EXPR)->expr_type != ExprType::TABLE)
throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, "Cannot convert new tree-like JoinExpr to old AST");
auto left = get(LEFT_EXPR)->convertToOld(), right = get(RIGHT_EXPR)->convertToOld(); // ASTExpressionList's
list->children.insert(list->children.end(), left->children.begin(), left->children.end()); // Insert all the previously parsed left subtree
list->children.emplace_back(right->children[0]); // Insert only first (single) ASTTablesInSelectQueryElement which should contain only ASTTableExpression
auto element = std::make_shared<ASTTableJoin>();
switch (op_mode)
{
case JoinOpMode::DEFAULT:
element->locality = ASTTableJoin::Locality::Unspecified;
break;
case JoinOpMode::GLOBAL:
element->locality = ASTTableJoin::Locality::Global;
break;
case JoinOpMode::LOCAL:
element->locality = ASTTableJoin::Locality::Local;
break;
}
switch (op_type)
{
case JoinOpType::CROSS:
element->kind = ASTTableJoin::Kind::Cross;
break;
case JoinOpType::FULL:
element->kind = ASTTableJoin::Kind::Full;
break;
case JoinOpType::FULL_ALL:
element->kind = ASTTableJoin::Kind::Full;
element->strictness = ASTTableJoin::Strictness::All;
break;
case JoinOpType::FULL_ANY:
element->kind = ASTTableJoin::Kind::Full;
element->strictness = ASTTableJoin::Strictness::Any;
break;
case JoinOpType::INNER:
element->kind = ASTTableJoin::Kind::Inner;
break;
case JoinOpType::INNER_ALL:
element->kind = ASTTableJoin::Kind::Inner;
element->strictness = ASTTableJoin::Strictness::All;
break;
case JoinOpType::INNER_ANY:
element->kind = ASTTableJoin::Kind::Inner;
element->strictness = ASTTableJoin::Strictness::Any;
break;
case JoinOpType::INNER_ASOF:
element->kind = ASTTableJoin::Kind::Inner;
element->strictness = ASTTableJoin::Strictness::Asof;
break;
case JoinOpType::LEFT:
element->kind = ASTTableJoin::Kind::Left;
break;
case JoinOpType::LEFT_ALL:
element->kind = ASTTableJoin::Kind::Left;
element->strictness = ASTTableJoin::Strictness::All;
break;
case JoinOpType::LEFT_ANTI:
element->kind = ASTTableJoin::Kind::Left;
element->strictness = ASTTableJoin::Strictness::Anti;
break;
case JoinOpType::LEFT_ANY:
element->kind = ASTTableJoin::Kind::Left;
element->strictness = ASTTableJoin::Strictness::Any;
break;
case JoinOpType::LEFT_ASOF:
element->kind = ASTTableJoin::Kind::Left;
element->strictness = ASTTableJoin::Strictness::Asof;
break;
case JoinOpType::LEFT_SEMI:
element->kind = ASTTableJoin::Kind::Left;
element->strictness = ASTTableJoin::Strictness::Semi;
break;
case JoinOpType::RIGHT:
element->kind = ASTTableJoin::Kind::Right;
break;
case JoinOpType::RIGHT_ANTI:
element->kind = ASTTableJoin::Kind::Right;
element->strictness = ASTTableJoin::Strictness::Anti;
break;
case JoinOpType::RIGHT_ALL:
element->kind = ASTTableJoin::Kind::Right;
element->strictness = ASTTableJoin::Strictness::All;
break;
case JoinOpType::RIGHT_ANY:
element->kind = ASTTableJoin::Kind::Right;
element->strictness = ASTTableJoin::Strictness::Any;
break;
case JoinOpType::RIGHT_ASOF:
element->kind = ASTTableJoin::Kind::Right;
element->strictness = ASTTableJoin::Strictness::Asof;
break;
case JoinOpType::RIGHT_SEMI:
element->kind = ASTTableJoin::Kind::Right;
element->strictness = ASTTableJoin::Strictness::Semi;
break;
}
if (has(CONSTRAINT))
{
const auto * constraint = get<JoinConstraintClause>(CONSTRAINT);
switch(constraint->getType())
{
case JoinConstraintClause::ConstraintType::ON:
element->on_expression = constraint->convertToOld();
if (element->on_expression->children.size() > 1)
throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, "Cannot convert JoinExpr with more than one ON expression");
element->on_expression = element->on_expression->children[0];
element->children.push_back(element->on_expression);
break;
case JoinConstraintClause::ConstraintType::USING:
element->using_expression_list = constraint->convertToOld();
element->children.push_back(element->using_expression_list);
break;
}
}
list->children.back()->children.emplace_back(element);
list->children.back()->as<ASTTablesInSelectQueryElement>()->table_join = element;
}
return list;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitJoinConstraintClause(ClickHouseParser::JoinConstraintClauseContext *ctx)
{
return std::make_shared<JoinConstraintClause>(
ctx->ON() ? JoinConstraintClause::ConstraintType::ON : JoinConstraintClause::ConstraintType::USING,
visit(ctx->columnExprList()));
}
antlrcpp::Any ParseTreeVisitor::visitJoinExprCrossOp(ClickHouseParser::JoinExprCrossOpContext *ctx)
{
auto [op, mode] = std::pair<JoinExpr::JoinOpType, JoinExpr::JoinOpMode>(visit(ctx->joinOpCross()));
return JoinExpr::createJoinOp(visit(ctx->joinExpr(0)), visit(ctx->joinExpr(1)), op, mode, nullptr);
}
antlrcpp::Any ParseTreeVisitor::visitJoinExprOp(ClickHouseParser::JoinExprOpContext *ctx)
{
auto mode = JoinExpr::JoinOpMode::DEFAULT;
auto op = ctx->joinOp() ? visit(ctx->joinOp()).as<JoinExpr::JoinOpType>() : JoinExpr::JoinOpType::INNER;
if (ctx->GLOBAL()) mode = JoinExpr::JoinOpMode::GLOBAL;
else if (ctx->LOCAL()) mode = JoinExpr::JoinOpMode::LOCAL;
return JoinExpr::createJoinOp(visit(ctx->joinExpr(0)), visit(ctx->joinExpr(1)), op, mode, visit(ctx->joinConstraintClause()));
}
antlrcpp::Any ParseTreeVisitor::visitJoinExprParens(ClickHouseParser::JoinExprParensContext *ctx)
{
return visit(ctx->joinExpr());
}
antlrcpp::Any ParseTreeVisitor::visitJoinExprTable(ClickHouseParser::JoinExprTableContext *ctx)
{
auto sample = ctx->sampleClause() ? visit(ctx->sampleClause()).as<PtrTo<SampleClause>>() : nullptr;
return JoinExpr::createTableExpr(visit(ctx->tableExpr()), sample, !!ctx->FINAL());
}
antlrcpp::Any ParseTreeVisitor::visitJoinOpCross(ClickHouseParser::JoinOpCrossContext *ctx)
{
std::pair<JoinExpr::JoinOpType, JoinExpr::JoinOpMode> op{
JoinExpr::JoinOpType::CROSS, JoinExpr::JoinOpMode::DEFAULT};
if (ctx->GLOBAL()) op.second = JoinExpr::JoinOpMode::GLOBAL;
else if (ctx->LOCAL()) op.second = JoinExpr::JoinOpMode::LOCAL;
return op;
}
antlrcpp::Any ParseTreeVisitor::visitJoinOpFull(ClickHouseParser::JoinOpFullContext *ctx)
{
if (ctx->ALL()) return JoinExpr::JoinOpType::FULL_ALL;
if (ctx->ANY()) return JoinExpr::JoinOpType::FULL_ANY;
return JoinExpr::JoinOpType::FULL;
}
antlrcpp::Any ParseTreeVisitor::visitJoinOpInner(ClickHouseParser::JoinOpInnerContext *ctx)
{
if (ctx->ALL()) return JoinExpr::JoinOpType::INNER_ALL;
if (ctx->ANY()) return JoinExpr::JoinOpType::INNER_ANY;
if (ctx->ASOF()) return JoinExpr::JoinOpType::INNER_ASOF;
return JoinExpr::JoinOpType::INNER;
}
antlrcpp::Any ParseTreeVisitor::visitJoinOpLeftRight(ClickHouseParser::JoinOpLeftRightContext *ctx)
{
if (ctx->LEFT())
{
if (ctx->SEMI()) return JoinExpr::JoinOpType::LEFT_SEMI;
if (ctx->ALL()) return JoinExpr::JoinOpType::LEFT_ALL;
if (ctx->ANTI()) return JoinExpr::JoinOpType::LEFT_ANTI;
if (ctx->ANY()) return JoinExpr::JoinOpType::LEFT_ANY;
if (ctx->ASOF()) return JoinExpr::JoinOpType::LEFT_ASOF;
return JoinExpr::JoinOpType::LEFT;
}
else if (ctx->RIGHT())
{
if (ctx->SEMI()) return JoinExpr::JoinOpType::RIGHT_SEMI;
if (ctx->ALL()) return JoinExpr::JoinOpType::RIGHT_ALL;
if (ctx->ANTI()) return JoinExpr::JoinOpType::RIGHT_ANTI;
if (ctx->ANY()) return JoinExpr::JoinOpType::RIGHT_ANY;
if (ctx->ASOF()) return JoinExpr::JoinOpType::RIGHT_ASOF;
return JoinExpr::JoinOpType::RIGHT;
}
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitSampleClause(ClickHouseParser::SampleClauseContext *ctx)
{
auto offset = ctx->ratioExpr().size() == 2 ? visit(ctx->ratioExpr(1)).as<PtrTo<RatioExpr>>() : nullptr;
return std::make_shared<SampleClause>(visit(ctx->ratioExpr(0)), offset);
}
}

View File

@ -0,0 +1,103 @@
#pragma once
#include <Parsers/New/AST/INode.h>
namespace DB::AST
{
class JoinConstraintClause : public SimpleClause<ColumnExprList>
{
public:
enum class ConstraintType
{
ON,
USING,
};
JoinConstraintClause(ConstraintType type, PtrTo<ColumnExprList> list);
auto getType() const { return type; }
private:
const ConstraintType type;
};
class SampleClause : public INode
{
public:
SampleClause(PtrTo<RatioExpr> ratio_, PtrTo<RatioExpr> offset_);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
RATIO = 0, // RatioExpr
OFFSET = 1, // RatioExpr (optional)
};
};
class JoinExpr : public INode
{
public:
enum class JoinOpType
{
INNER,
INNER_ALL,
INNER_ANY,
INNER_ASOF,
LEFT,
LEFT_SEMI,
LEFT_ALL,
LEFT_ANTI,
LEFT_ANY,
LEFT_ASOF,
RIGHT,
RIGHT_SEMI,
RIGHT_ALL,
RIGHT_ANTI,
RIGHT_ANY,
RIGHT_ASOF,
FULL,
FULL_ALL,
FULL_ANY,
CROSS,
};
enum class JoinOpMode
{
DEFAULT, // actual mode depends on setting's 'distributed_product_mode' value
GLOBAL,
LOCAL,
};
static PtrTo<JoinExpr> createTableExpr(PtrTo<TableExpr> expr, PtrTo<SampleClause> clause, bool final);
static PtrTo<JoinExpr> createJoinOp(PtrTo<JoinExpr> left_expr, PtrTo<JoinExpr> right_expr, JoinOpType op, JoinOpMode mode, PtrTo<JoinConstraintClause> clause);
ASTPtr convertToOld() const override; // returns topologically sorted elements as ASTExpressionList
private:
enum ChildIndex : UInt8
{
TABLE = 0, // TableExpr
SAMPLE = 1, // SampleClause (optional)
LEFT_EXPR = 0, // JoinExpr
RIGHT_EXPR = 1, // JoinExpr
CONSTRAINT = 2, // JoinConstraintClause
};
enum class ExprType
{
TABLE,
JOIN_OP,
};
const ExprType expr_type;
const JoinOpType op_type = JoinOpType::INNER;
const JoinOpMode op_mode = JoinOpMode::DEFAULT;
const bool final = false;
JoinExpr(ExprType type, bool final, PtrList exprs);
JoinExpr(ExprType type, JoinOpType op, JoinOpMode mode, PtrList exprs);
};
}

View File

@ -0,0 +1,56 @@
#include <Parsers/New/AST/KillQuery.h>
#include <Parsers/ASTKillQueryQuery.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
// static
PtrTo<KillQuery> KillQuery::createMutation(PtrTo<ClusterClause> cluster, bool sync, bool test, PtrTo<WhereClause> where)
{
PtrTo<KillQuery> query(new KillQuery(cluster, QueryType::MUTATION, {where}));
query->sync = sync;
query->test = test;
return query;
}
KillQuery::KillQuery(PtrTo<ClusterClause> cluster, QueryType type, PtrList exprs) : DDLQuery(cluster, exprs), query_type(type)
{
}
ASTPtr KillQuery::convertToOld() const
{
auto query = std::make_shared<ASTKillQueryQuery>();
query->cluster = cluster_name;
switch(query_type)
{
case QueryType::MUTATION:
query->type = ASTKillQueryQuery::Type::Mutation;
query->sync = sync;
query->test = test;
query->where_expression = get(WHERE)->convertToOld();
query->children.push_back(query->where_expression);
break;
}
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitKillMutationStmt(ClickHouseParser::KillMutationStmtContext * ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
return KillQuery::createMutation(cluster, !!ctx->SYNC(), !!ctx->TEST(), visit(ctx->whereClause()));
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <Parsers/New/AST/DDLQuery.h>
namespace DB::AST
{
class KillQuery : public DDLQuery
{
public:
static PtrTo<KillQuery> createMutation(PtrTo<ClusterClause> cluster, bool sync, bool test, PtrTo<WhereClause> where);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
WHERE = 0, // WhereClause
};
enum class QueryType
{
MUTATION,
};
const QueryType query_type;
bool sync = false, test = false;
KillQuery(PtrTo<ClusterClause> cluster, QueryType type, PtrList exprs);
};
}

View File

@ -0,0 +1,39 @@
#include <Parsers/New/AST/LimitExpr.h>
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
LimitExpr::LimitExpr(PtrTo<ColumnExpr> limit, PtrTo<ColumnExpr> offset) : INode{limit, offset}
{
}
ASTPtr LimitExpr::convertToOld() const
{
auto list = std::make_shared<ASTExpressionList>();
if (has(OFFSET)) list->children.push_back(get(OFFSET)->convertToOld());
list->children.push_back(get(LIMIT)->convertToOld());
return list;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitLimitExpr(ClickHouseParser::LimitExprContext *ctx)
{
if (ctx->columnExpr().size() == 2)
return std::make_shared<LimitExpr>(visit(ctx->columnExpr(0)), visit(ctx->columnExpr(1)));
else
return std::make_shared<LimitExpr>(visit(ctx->columnExpr(0)).as<PtrTo<ColumnExpr>>());
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <Parsers/New/AST/INode.h>
namespace DB::AST
{
class LimitExpr : public INode
{
public:
explicit LimitExpr(PtrTo<ColumnExpr> limit, PtrTo<ColumnExpr> offset = nullptr);
ASTPtr convertToOld() const override;
private:
enum ChildIndex : UInt8
{
LIMIT = 0, // ColumnExpr
OFFSET = 1, // ColumnExpr (optional)
};
};
}

View File

@ -0,0 +1,222 @@
#include <Parsers/New/AST/Literal.h>
#include <IO/ReadHelpers.h>
#include <IO/WriteBufferFromString.h>
#include <IO/WriteHelpers.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
// static
PtrTo<Literal> Literal::createNull()
{
return PtrTo<Literal>(new Literal(LiteralType::NULL_LITERAL, String()));
}
// static
PtrTo<NumberLiteral> Literal::createNumber(antlr4::tree::TerminalNode * literal, bool negative)
{
auto number = std::make_shared<NumberLiteral>(literal);
if (negative) number->makeNegative();
return number;
}
// static
PtrTo<NumberLiteral> Literal::createNumber(const String & literal)
{
bool has_minus = literal[0] == '-';
auto number = std::make_shared<NumberLiteral>(has_minus ? literal.substr(1) : literal);
if (has_minus) number->makeNegative();
return number;
}
// static
PtrTo<StringLiteral> Literal::createString(antlr4::tree::TerminalNode * literal)
{
return std::make_shared<StringLiteral>(literal);
}
// static
PtrTo<StringLiteral> Literal::createString(const String & literal)
{
return std::make_shared<StringLiteral>(literal);
}
Literal::Literal(LiteralType type_, const String & token_) : token(token_), type(type_)
{
}
ASTPtr Literal::convertToOld() const
{
auto as_field = [this] () -> Field
{
switch(type)
{
case LiteralType::NULL_LITERAL:
return Field(Null());
case LiteralType::NUMBER:
{
const auto * number = this->as<NumberLiteral>();
if (!number->isNegative())
if (auto value = number->as<UInt64>()) return Field(*value);
if (auto value = number->as<Int64>()) return Field(*value);
if (auto value = number->as<Float64>()) return Field(*value);
return Field();
}
case LiteralType::STRING:
return asString();
}
__builtin_unreachable();
};
return std::make_shared<ASTLiteral>(as_field());
}
String Literal::toString() const
{
WriteBufferFromOwnString wb;
writeEscapedString(token, wb);
return type == LiteralType::STRING ? "'" + wb.str() + "'" : wb.str();
}
NumberLiteral::NumberLiteral(antlr4::tree::TerminalNode * literal) : Literal(LiteralType::NUMBER, literal->getSymbol()->getText())
{
}
NumberLiteral::NumberLiteral(const String & literal) : Literal(LiteralType::NUMBER, literal)
{
}
String NumberLiteral::toString() const
{
return (minus ? String("-") : String()) + Literal::toString();
}
ASTSampleRatio::Rational NumberLiteral::convertToOldRational() const
{
UInt64 num_before = 0;
UInt64 num_after = 0;
Int64 exponent = 0;
const char * pos = token.data(), * end = token.data() + token.size();
const char * pos_after_first_num = tryReadIntText(num_before, pos, end);
bool has_num_before_point [[maybe_unused]] = pos_after_first_num > pos;
pos = pos_after_first_num;
bool has_point = pos < end && *pos == '.';
if (has_point)
++pos;
assert (has_num_before_point || has_point);
size_t number_of_digits_after_point = 0;
if (has_point)
{
const char * pos_after_second_num = tryReadIntText(num_after, pos, end);
number_of_digits_after_point = pos_after_second_num - pos;
pos = pos_after_second_num;
}
bool has_exponent = pos < end && (*pos == 'e' || *pos == 'E');
if (has_exponent)
{
++pos;
const char * pos_after_exponent [[maybe_unused]] = tryReadIntText(exponent, pos, end);
assert (pos_after_exponent != pos);
}
ASTSampleRatio::Rational res;
res.numerator = num_before * intExp10(number_of_digits_after_point) + num_after;
res.denominator = intExp10(number_of_digits_after_point);
if (exponent > 0)
res.numerator *= intExp10(exponent);
if (exponent < 0)
res.denominator *= intExp10(-exponent);
return res;
}
StringLiteral::StringLiteral(antlr4::tree::TerminalNode * literal) : Literal(LiteralType::STRING, literal->getSymbol()->getText())
{
String s;
ReadBufferFromMemory in(token.data(), token.size());
readQuotedStringWithSQLStyle(s, in);
assert(in.count() == token.size());
token = s;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitFloatingLiteral(ClickHouseParser::FloatingLiteralContext * ctx)
{
if (ctx->FLOATING_LITERAL()) return Literal::createNumber(ctx->FLOATING_LITERAL());
const auto * dot = ctx->DOT()->getSymbol();
if (!ctx->DECIMAL_LITERAL().empty())
{
// .1234
if (dot->getTokenIndex() < ctx->DECIMAL_LITERAL(0)->getSymbol()->getTokenIndex())
return Literal::createNumber(dot->getText() + ctx->DECIMAL_LITERAL(0)->getSymbol()->getText());
// 1234.
else if (ctx->DECIMAL_LITERAL().size() == 1 && !ctx->OCTAL_LITERAL())
return Literal::createNumber(ctx->DECIMAL_LITERAL(0)->getSymbol()->getText() + dot->getText());
// 1234.1234
else if (ctx->DECIMAL_LITERAL().size() == 2)
return Literal::createNumber(
ctx->DECIMAL_LITERAL(0)->getSymbol()->getText() + dot->getText() + ctx->DECIMAL_LITERAL(1)->getSymbol()->getText());
// 1234.0123
else
return Literal::createNumber(
ctx->DECIMAL_LITERAL(0)->getSymbol()->getText() + dot->getText() + ctx->OCTAL_LITERAL()->getSymbol()->getText());
}
else
// .0123
return Literal::createNumber(dot->getText() + ctx->OCTAL_LITERAL()->getSymbol()->getText());
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitLiteral(ClickHouseParser::LiteralContext * ctx)
{
if (ctx->NULL_SQL())
return Literal::createNull();
if (ctx->STRING_LITERAL())
return std::static_pointer_cast<Literal>(Literal::createString(ctx->STRING_LITERAL()));
if (ctx->numberLiteral())
return std::static_pointer_cast<Literal>(visit(ctx->numberLiteral()).as<PtrTo<NumberLiteral>>());
__builtin_unreachable();
}
antlrcpp::Any ParseTreeVisitor::visitNumberLiteral(ClickHouseParser::NumberLiteralContext *ctx)
{
if (ctx->floatingLiteral())
{
auto number = visit(ctx->floatingLiteral()).as<PtrTo<NumberLiteral>>();
if (ctx->DASH()) number->makeNegative();
return number;
}
if (ctx->OCTAL_LITERAL()) return Literal::createNumber(ctx->OCTAL_LITERAL(), !!ctx->DASH());
if (ctx->DECIMAL_LITERAL()) return Literal::createNumber(ctx->DECIMAL_LITERAL(), !!ctx->DASH());
if (ctx->HEXADECIMAL_LITERAL()) return Literal::createNumber(ctx->HEXADECIMAL_LITERAL(), !!ctx->DASH());
if (ctx->INF()) return Literal::createNumber(ctx->INF(), !!ctx->DASH());
if (ctx->NAN_SQL()) return Literal::createNumber(ctx->NAN_SQL());
__builtin_unreachable();
}
}

View File

@ -0,0 +1,96 @@
#pragma once
#include <Parsers/New/AST/INode.h>
#include <Core/Field.h>
#include <Parsers/ASTSampleRatio.h>
#include <Token.h>
#include <tree/TerminalNode.h>
#include <sstream>
namespace DB::AST
{
class Literal : public INode
{
public:
enum class LiteralType
{
NULL_LITERAL,
NUMBER,
STRING,
};
static PtrTo<Literal> createNull();
static PtrTo<NumberLiteral> createNumber(antlr4::tree::TerminalNode * literal, bool negative = false);
static PtrTo<NumberLiteral> createNumber(const String& literal); // checks first symbol for '-' character
static PtrTo<StringLiteral> createString(antlr4::tree::TerminalNode * literal);
static PtrTo<StringLiteral> createString(const String& literal); // without quotes
ASTPtr convertToOld() const override;
String toString() const override;
bool is(LiteralType what) const { return type == what; }
protected:
String token; // STRING is stored without quotes and interpolated with escape-sequences.
Literal(LiteralType type, const String & token);
template <typename T>
std::optional<T> asNumber(bool minus) const
{
T number;
std::stringstream ss(String(minus ? "-" : "+") + token);
if (token.size() > 2 && (token[1] == 'x' || token[1] == 'X')) ss >> std::hex >> number;
else if (token.size() > 1 && (token[0] == '0')) ss >> std::oct >> number;
else ss >> number;
if (ss.fail() || !ss.eof())
return {};
return number;
}
auto asString() const { return token; }
private:
LiteralType type;
String dumpInfo() const override { return token; }
};
class NumberLiteral : public Literal
{
public:
explicit NumberLiteral(antlr4::tree::TerminalNode * literal);
explicit NumberLiteral(const String & literal);
String toString() const override;
void makeNegative() { minus = true; }
bool isNegative() const { return minus; }
template <typename T> std::optional<T> as() const { return asNumber<T>(minus); }
ASTSampleRatio::Rational convertToOldRational() const;
private:
bool minus = false;
};
class StringLiteral : public Literal
{
public:
explicit StringLiteral(antlr4::tree::TerminalNode * literal);
explicit StringLiteral(const String & literal) : Literal(LiteralType::STRING, literal) {}
template <typename T>
T as() const
{
return asString();
}
};
}

View File

@ -0,0 +1,59 @@
#include <Parsers/New/AST/OptimizeQuery.h>
#include <Interpreters/StorageID.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTOptimizeQuery.h>
#include <Parsers/New/AST/AlterTableQuery.h>
#include <Parsers/New/AST/ColumnExpr.h>
#include <Parsers/New/AST/Identifier.h>
#include <Parsers/New/AST/Literal.h>
#include <Parsers/New/ParseTreeVisitor.h>
namespace DB::AST
{
OptimizeQuery::OptimizeQuery(PtrTo<ClusterClause> cluster, PtrTo<TableIdentifier> identifier, PtrTo<PartitionClause> clause, bool final_, bool deduplicate_)
: DDLQuery(cluster, {identifier, clause}), final(final_), deduplicate(deduplicate_)
{
}
ASTPtr OptimizeQuery::convertToOld() const
{
auto query = std::make_shared<ASTOptimizeQuery>();
{
auto table_id = getTableIdentifier(get(TABLE)->convertToOld());
query->database = table_id.database_name;
query->table = table_id.table_name;
query->uuid = table_id.uuid;
}
if (has(PARTITION))
{
query->partition = get(PARTITION)->convertToOld();
query->children.push_back(query->partition);
}
query->final = final;
query->deduplicate = deduplicate;
query->cluster = cluster_name;
return query;
}
}
namespace DB
{
using namespace AST;
antlrcpp::Any ParseTreeVisitor::visitOptimizeStmt(ClickHouseParser::OptimizeStmtContext *ctx)
{
auto cluster = ctx->clusterClause() ? visit(ctx->clusterClause()).as<PtrTo<ClusterClause>>() : nullptr;
auto clause = ctx->partitionClause() ? visit(ctx->partitionClause()).as<PtrTo<PartitionClause>>() : nullptr;
return std::make_shared<OptimizeQuery>(cluster, visit(ctx->tableIdentifier()), clause, !!ctx->FINAL(), !!ctx->DEDUPLICATE());
}
}

Some files were not shown because too many files have changed in this diff Show More