Merge remote-tracking branch 'upstream/master' into update_libunwind

This commit is contained in:
Nikita Lapkov 2019-03-29 10:50:26 +00:00
commit 59748db2ff
116 changed files with 2792 additions and 1399 deletions

View File

@ -26,7 +26,7 @@
* Исправлено undefined behaviour в функции `dictIsIn` для словарей типа `cache`. [#4515](https://github.com/yandex/ClickHouse/pull/4515) ([alesapin](https://github.com/alesapin)) * Исправлено undefined behaviour в функции `dictIsIn` для словарей типа `cache`. [#4515](https://github.com/yandex/ClickHouse/pull/4515) ([alesapin](https://github.com/alesapin))
* Исправлен deadlock в случае, если запрос SELECT блокирует одну и ту же таблицу несколько раз (например - из разных потоков, либо при выполнении разных подзапросов) и одновременно с этим производится DDL запрос. [#4535](https://github.com/yandex/ClickHouse/pull/4535) ([Alex Zatelepin](https://github.com/ztlpn)) * Исправлен deadlock в случае, если запрос SELECT блокирует одну и ту же таблицу несколько раз (например - из разных потоков, либо при выполнении разных подзапросов) и одновременно с этим производится DDL запрос. [#4535](https://github.com/yandex/ClickHouse/pull/4535) ([Alex Zatelepin](https://github.com/ztlpn))
* Настройка `compile_expressions` выключена по-умолчанию до тех пор, пока мы не зафиксируем исходники используемой библиотеки `LLVM` и не будем проверять её под `ASan` (сейчас библиотека LLVM берётся из системы). [#4579](https://github.com/yandex/ClickHouse/pull/4579) ([alesapin](https://github.com/alesapin)) * Настройка `compile_expressions` выключена по-умолчанию до тех пор, пока мы не зафиксируем исходники используемой библиотеки `LLVM` и не будем проверять её под `ASan` (сейчас библиотека LLVM берётся из системы). [#4579](https://github.com/yandex/ClickHouse/pull/4579) ([alesapin](https://github.com/alesapin))
* Исправлено падение по `std::terminate`, если `invalidate_query` для внешних словарей с истоником `clickhouse` вернул неправильный результат (пустой; более чем одну строку; более чем один столбец). Исправлена ошибка, из-за которой запрос `invalidate_query` производился каждые пять секунд, независимо от указанного `lifetime`. [#4583](https://github.com/yandex/ClickHouse/pull/4583) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Исправлено падение по `std::terminate`, если `invalidate_query` для внешних словарей с источником `clickhouse` вернул неправильный результат (пустой; более чем одну строку; более чем один столбец). Исправлена ошибка, из-за которой запрос `invalidate_query` производился каждые пять секунд, независимо от указанного `lifetime`. [#4583](https://github.com/yandex/ClickHouse/pull/4583) ([alexey-milovidov](https://github.com/alexey-milovidov))
* Исправлен deadlock в случае, если запрос `invalidate_query` для внешнего словаря с источником `clickhouse` использовал таблицу `system.dictionaries` или базу данных типа `Dictionary` (редкий случай). [#4599](https://github.com/yandex/ClickHouse/pull/4599) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Исправлен deadlock в случае, если запрос `invalidate_query` для внешнего словаря с источником `clickhouse` использовал таблицу `system.dictionaries` или базу данных типа `Dictionary` (редкий случай). [#4599](https://github.com/yandex/ClickHouse/pull/4599) ([alexey-milovidov](https://github.com/alexey-milovidov))
* Исправлена работа CROSS JOIN с пустым WHERE [#4598](https://github.com/yandex/ClickHouse/pull/4598) ([Artem Zuikov](https://github.com/4ertus2)) * Исправлена работа CROSS JOIN с пустым WHERE [#4598](https://github.com/yandex/ClickHouse/pull/4598) ([Artem Zuikov](https://github.com/4ertus2))
* Исправлен segfault в функции `replicate` с константным аргументом. [#4603](https://github.com/yandex/ClickHouse/pull/4603) ([alexey-milovidov](https://github.com/alexey-milovidov)) * Исправлен segfault в функции `replicate` с константным аргументом. [#4603](https://github.com/yandex/ClickHouse/pull/4603) ([alexey-milovidov](https://github.com/alexey-milovidov))

View File

@ -1,8 +1,11 @@
project (ClickHouse) project(ClickHouse)
cmake_minimum_required (VERSION 3.3) cmake_minimum_required(VERSION 3.3)
cmake_policy(SET CMP0023 NEW) cmake_policy(SET CMP0023 NEW)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1) # Write compile_commands.json
set(CMAKE_LINK_DEPENDS_NO_SHARED 1) # Do not relink all depended targets on .so
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Debug;Release;MinSizeRel" CACHE STRING "" FORCE)
set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Generate debug library name with a postfix.") # To be consistent with CMakeLists from contrib libs.
option(ENABLE_IPO "Enable inter-procedural optimization (aka LTO)" OFF) # need cmake 3.9+ option(ENABLE_IPO "Enable inter-procedural optimization (aka LTO)" OFF) # need cmake 3.9+
if(ENABLE_IPO) if(ENABLE_IPO)
@ -38,9 +41,6 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND NOT EXISTS "${ClickHouse_SOURC
message (FATAL_ERROR "Submodules are not initialized. Run\n\tgit submodule update --init --recursive") message (FATAL_ERROR "Submodules are not initialized. Run\n\tgit submodule update --init --recursive")
endif () endif ()
# Write compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
include (cmake/find_ccache.cmake) include (cmake/find_ccache.cmake)
if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "None") if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "None")
@ -50,8 +50,6 @@ endif ()
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UC) string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UC)
message (STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") message (STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
set (CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Debug;Release;MinSizeRel" CACHE STRING "" FORCE)
set (CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Generate debug library name with a postfix.") # To be consistent with CMakeLists from contrib libs.
option (USE_STATIC_LIBRARIES "Set to FALSE to use shared libraries" ON) option (USE_STATIC_LIBRARIES "Set to FALSE to use shared libraries" ON)
option (MAKE_STATIC_LIBRARIES "Set to FALSE to make shared libraries" ${USE_STATIC_LIBRARIES}) option (MAKE_STATIC_LIBRARIES "Set to FALSE to make shared libraries" ${USE_STATIC_LIBRARIES})

View File

@ -93,6 +93,7 @@ if (CLICKHOUSE_ONE_SHARED)
target_link_libraries(clickhouse-lib ${CLICKHOUSE_SERVER_LINK} ${CLICKHOUSE_CLIENT_LINK} ${CLICKHOUSE_LOCAL_LINK} ${CLICKHOUSE_BENCHMARK_LINK} ${CLICKHOUSE_PERFORMANCE_TEST_LINK} ${CLICKHOUSE_COPIER_LINK} ${CLICKHOUSE_EXTRACT_FROM_CONFIG_LINK} ${CLICKHOUSE_COMPRESSOR_LINK} ${CLICKHOUSE_FORMAT_LINK} ${CLICKHOUSE_OBFUSCATOR_LINK} ${CLICKHOUSE_COMPILER_LINK} ${CLICKHOUSE_ODBC_BRIDGE_LINK}) target_link_libraries(clickhouse-lib ${CLICKHOUSE_SERVER_LINK} ${CLICKHOUSE_CLIENT_LINK} ${CLICKHOUSE_LOCAL_LINK} ${CLICKHOUSE_BENCHMARK_LINK} ${CLICKHOUSE_PERFORMANCE_TEST_LINK} ${CLICKHOUSE_COPIER_LINK} ${CLICKHOUSE_EXTRACT_FROM_CONFIG_LINK} ${CLICKHOUSE_COMPRESSOR_LINK} ${CLICKHOUSE_FORMAT_LINK} ${CLICKHOUSE_OBFUSCATOR_LINK} ${CLICKHOUSE_COMPILER_LINK} ${CLICKHOUSE_ODBC_BRIDGE_LINK})
target_include_directories(clickhouse-lib ${CLICKHOUSE_SERVER_INCLUDE} ${CLICKHOUSE_CLIENT_INCLUDE} ${CLICKHOUSE_LOCAL_INCLUDE} ${CLICKHOUSE_BENCHMARK_INCLUDE} ${CLICKHOUSE_PERFORMANCE_TEST_INCLUDE} ${CLICKHOUSE_COPIER_INCLUDE} ${CLICKHOUSE_EXTRACT_FROM_CONFIG_INCLUDE} ${CLICKHOUSE_COMPRESSOR_INCLUDE} ${CLICKHOUSE_FORMAT_INCLUDE} ${CLICKHOUSE_OBFUSCATOR_INCLUDE} ${CLICKHOUSE_COMPILER_INCLUDE} ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE}) target_include_directories(clickhouse-lib ${CLICKHOUSE_SERVER_INCLUDE} ${CLICKHOUSE_CLIENT_INCLUDE} ${CLICKHOUSE_LOCAL_INCLUDE} ${CLICKHOUSE_BENCHMARK_INCLUDE} ${CLICKHOUSE_PERFORMANCE_TEST_INCLUDE} ${CLICKHOUSE_COPIER_INCLUDE} ${CLICKHOUSE_EXTRACT_FROM_CONFIG_INCLUDE} ${CLICKHOUSE_COMPRESSOR_INCLUDE} ${CLICKHOUSE_FORMAT_INCLUDE} ${CLICKHOUSE_OBFUSCATOR_INCLUDE} ${CLICKHOUSE_COMPILER_INCLUDE} ${CLICKHOUSE_ODBC_BRIDGE_INCLUDE})
set_target_properties(clickhouse-lib PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR} VERSION ${VERSION_SO} OUTPUT_NAME clickhouse DEBUG_POSTFIX "") set_target_properties(clickhouse-lib PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR} VERSION ${VERSION_SO} OUTPUT_NAME clickhouse DEBUG_POSTFIX "")
install (TARGETS clickhouse-lib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT clickhouse)
endif() endif()
if (CLICKHOUSE_SPLIT_BINARY) if (CLICKHOUSE_SPLIT_BINARY)

View File

@ -1,5 +1,11 @@
#!/bin/sh #!/bin/sh
# Helper for split build mode.
# Allows to run commands like
# clickhouse client
# clickhouse server
# ...
set -e set -e
CMD=$1 CMD=$1
shift shift

View File

@ -39,7 +39,7 @@ private:
"DATABASES", "LIKE", "PROCESSLIST", "CASE", "WHEN", "THEN", "ELSE", "END", "DESCRIBE", "DESC", "USE", "SET", "OPTIMIZE", "FINAL", "DEDUPLICATE", "DATABASES", "LIKE", "PROCESSLIST", "CASE", "WHEN", "THEN", "ELSE", "END", "DESCRIBE", "DESC", "USE", "SET", "OPTIMIZE", "FINAL", "DEDUPLICATE",
"INSERT", "VALUES", "SELECT", "DISTINCT", "SAMPLE", "ARRAY", "JOIN", "GLOBAL", "LOCAL", "ANY", "ALL", "INNER", "LEFT", "RIGHT", "FULL", "OUTER", "INSERT", "VALUES", "SELECT", "DISTINCT", "SAMPLE", "ARRAY", "JOIN", "GLOBAL", "LOCAL", "ANY", "ALL", "INNER", "LEFT", "RIGHT", "FULL", "OUTER",
"CROSS", "USING", "PREWHERE", "WHERE", "GROUP", "BY", "WITH", "TOTALS", "HAVING", "ORDER", "COLLATE", "LIMIT", "UNION", "AND", "OR", "ASC", "IN", "CROSS", "USING", "PREWHERE", "WHERE", "GROUP", "BY", "WITH", "TOTALS", "HAVING", "ORDER", "COLLATE", "LIMIT", "UNION", "AND", "OR", "ASC", "IN",
"KILL", "QUERY", "SYNC", "ASYNC", "TEST", "BETWEEN" "KILL", "QUERY", "SYNC", "ASYNC", "TEST", "BETWEEN", "TRUNCATE"
}; };
/// Words are fetched asynchonously. /// Words are fetched asynchonously.

View File

@ -67,10 +67,10 @@ struct UniqVariadicHash<false, true>
{ {
UInt64 hash; UInt64 hash;
const Columns & tuple_columns = static_cast<const ColumnTuple *>(columns[0])->getColumns(); const auto & tuple_columns = static_cast<const ColumnTuple *>(columns[0])->getColumns();
const ColumnPtr * column = tuple_columns.data(); const auto * column = tuple_columns.data();
const ColumnPtr * columns_end = column + num_args; const auto * columns_end = column + num_args;
{ {
StringRef value = column->get()->getDataAt(row_num); StringRef value = column->get()->getDataAt(row_num);
@ -116,10 +116,10 @@ struct UniqVariadicHash<true, true>
{ {
static inline UInt128 apply(size_t num_args, const IColumn ** columns, size_t row_num) static inline UInt128 apply(size_t num_args, const IColumn ** columns, size_t row_num)
{ {
const Columns & tuple_columns = static_cast<const ColumnTuple *>(columns[0])->getColumns(); const auto & tuple_columns = static_cast<const ColumnTuple *>(columns[0])->getColumns();
const ColumnPtr * column = tuple_columns.data(); const auto * column = tuple_columns.data();
const ColumnPtr * columns_end = column + num_args; const auto * columns_end = column + num_args;
SipHash hash; SipHash hash;

View File

@ -576,7 +576,7 @@ ColumnPtr ColumnArray::filterTuple(const Filter & filt, ssize_t result_size_hint
/// Make temporary arrays for each components of Tuple, then filter and collect back. /// Make temporary arrays for each components of Tuple, then filter and collect back.
size_t tuple_size = tuple.getColumns().size(); size_t tuple_size = tuple.tupleSize();
if (tuple_size == 0) if (tuple_size == 0)
throw Exception("Logical error: empty tuple", ErrorCodes::LOGICAL_ERROR); throw Exception("Logical error: empty tuple", ErrorCodes::LOGICAL_ERROR);
@ -941,7 +941,7 @@ ColumnPtr ColumnArray::replicateTuple(const Offsets & replicate_offsets) const
/// Make temporary arrays for each components of Tuple. In the same way as for Nullable. /// Make temporary arrays for each components of Tuple. In the same way as for Nullable.
size_t tuple_size = tuple.getColumns().size(); size_t tuple_size = tuple.tupleSize();
if (tuple_size == 0) if (tuple_size == 0)
throw Exception("Logical error: empty tuple", ErrorCodes::LOGICAL_ERROR); throw Exception("Logical error: empty tuple", ErrorCodes::LOGICAL_ERROR);

View File

@ -81,15 +81,15 @@ public:
bool hasEqualOffsets(const ColumnArray & other) const; bool hasEqualOffsets(const ColumnArray & other) const;
/** More efficient methods of manipulation */ /** More efficient methods of manipulation */
IColumn & getData() { return data->assumeMutableRef(); } IColumn & getData() { return *data; }
const IColumn & getData() const { return *data; } const IColumn & getData() const { return *data; }
IColumn & getOffsetsColumn() { return offsets->assumeMutableRef(); } IColumn & getOffsetsColumn() { return *offsets; }
const IColumn & getOffsetsColumn() const { return *offsets; } const IColumn & getOffsetsColumn() const { return *offsets; }
Offsets & ALWAYS_INLINE getOffsets() Offsets & ALWAYS_INLINE getOffsets()
{ {
return static_cast<ColumnOffsets &>(offsets->assumeMutableRef()).getData(); return static_cast<ColumnOffsets &>(*offsets).getData();
} }
const Offsets & ALWAYS_INLINE getOffsets() const const Offsets & ALWAYS_INLINE getOffsets() const
@ -124,8 +124,8 @@ public:
} }
private: private:
ColumnPtr data; WrappedPtr data;
ColumnPtr offsets; WrappedPtr offsets;
size_t ALWAYS_INLINE offsetAt(ssize_t i) const { return getOffsets()[i - 1]; } size_t ALWAYS_INLINE offsetAt(ssize_t i) const { return getOffsets()[i - 1]; }
size_t ALWAYS_INLINE sizeAt(ssize_t i) const { return getOffsets()[i] - getOffsets()[i - 1]; } size_t ALWAYS_INLINE sizeAt(ssize_t i) const { return getOffsets()[i] - getOffsets()[i - 1]; }

View File

@ -23,7 +23,7 @@ class ColumnConst final : public COWPtrHelper<IColumn, ColumnConst>
private: private:
friend class COWPtrHelper<IColumn, ColumnConst>; friend class COWPtrHelper<IColumn, ColumnConst>;
ColumnPtr data; WrappedPtr data;
size_t s; size_t s;
ColumnConst(const ColumnPtr & data, size_t s); ColumnConst(const ColumnPtr & data, size_t s);
@ -141,9 +141,8 @@ public:
const char * deserializeAndInsertFromArena(const char * pos) override const char * deserializeAndInsertFromArena(const char * pos) override
{ {
auto & mutable_data = data->assumeMutableRef(); auto res = data->deserializeAndInsertFromArena(pos);
auto res = mutable_data.deserializeAndInsertFromArena(pos); data->popBack(1);
mutable_data.popBack(1);
++s; ++s;
return res; return res;
} }
@ -208,11 +207,9 @@ public:
/// Not part of the common interface. /// Not part of the common interface.
IColumn & getDataColumn() { return data->assumeMutableRef(); } IColumn & getDataColumn() { return *data; }
const IColumn & getDataColumn() const { return *data; } const IColumn & getDataColumn() const { return *data; }
//MutableColumnPtr getDataColumnMutablePtr() { return data; }
const ColumnPtr & getDataColumnPtr() const { return data; } const ColumnPtr & getDataColumnPtr() const { return data; }
//ColumnPtr & getDataColumnPtr() { return data; }
Field getField() const { return getDataColumn()[0]; } Field getField() const { return getDataColumn()[0]; }

View File

@ -522,7 +522,7 @@ void ColumnLowCardinality::Index::insertPosition(UInt64 position)
while (position > getMaxPositionForCurrentType()) while (position > getMaxPositionForCurrentType())
expandType(); expandType();
positions->assumeMutableRef().insert(position); positions->insert(position);
checkSizeOfType(); checkSizeOfType();
} }
@ -540,7 +540,7 @@ void ColumnLowCardinality::Index::insertPositionsRange(const IColumn & column, U
convertPositions<ColumnType>(); convertPositions<ColumnType>();
if (size_of_type == sizeof(ColumnType)) if (size_of_type == sizeof(ColumnType))
positions->assumeMutableRef().insertRangeFrom(column, offset, limit); positions->insertRangeFrom(column, offset, limit);
else else
{ {
auto copy = [&](auto cur_type) auto copy = [&](auto cur_type)

View File

@ -149,10 +149,10 @@ public:
const IColumnUnique & getDictionary() const { return dictionary.getColumnUnique(); } const IColumnUnique & getDictionary() const { return dictionary.getColumnUnique(); }
const ColumnPtr & getDictionaryPtr() const { return dictionary.getColumnUniquePtr(); } const ColumnPtr & getDictionaryPtr() const { return dictionary.getColumnUniquePtr(); }
/// IColumnUnique & getUnique() { return static_cast<IColumnUnique &>(*column_unique->assumeMutable()); } /// IColumnUnique & getUnique() { return static_cast<IColumnUnique &>(*column_unique); }
/// ColumnPtr getUniquePtr() const { return column_unique; } /// ColumnPtr getUniquePtr() const { return column_unique; }
/// IColumn & getIndexes() { return idx.getPositions()->assumeMutableRef(); } /// IColumn & getIndexes() { return *idx.getPositions(); }
const IColumn & getIndexes() const { return *idx.getPositions(); } const IColumn & getIndexes() const { return *idx.getPositions(); }
const ColumnPtr & getIndexesPtr() const { return idx.getPositions(); } const ColumnPtr & getIndexesPtr() const { return idx.getPositions(); }
size_t getSizeOfIndexType() const { return idx.getSizeOfIndexType(); } size_t getSizeOfIndexType() const { return idx.getSizeOfIndexType(); }
@ -202,13 +202,13 @@ public:
explicit Index(ColumnPtr positions); explicit Index(ColumnPtr positions);
const ColumnPtr & getPositions() const { return positions; } const ColumnPtr & getPositions() const { return positions; }
ColumnPtr & getPositionsPtr() { return positions; } WrappedPtr & getPositionsPtr() { return positions; }
size_t getPositionAt(size_t row) const; size_t getPositionAt(size_t row) const;
void insertPosition(UInt64 position); void insertPosition(UInt64 position);
void insertPositionsRange(const IColumn & column, UInt64 offset, UInt64 limit); void insertPositionsRange(const IColumn & column, UInt64 offset, UInt64 limit);
void popBack(size_t n) { positions->assumeMutableRef().popBack(n); } void popBack(size_t n) { positions->popBack(n); }
void reserve(size_t n) { positions->assumeMutableRef().reserve(n); } void reserve(size_t n) { positions->reserve(n); }
UInt64 getMaxPositionForCurrentType() const; UInt64 getMaxPositionForCurrentType() const;
@ -224,7 +224,7 @@ public:
void countKeys(ColumnUInt64::Container & counts) const; void countKeys(ColumnUInt64::Container & counts) const;
private: private:
ColumnPtr positions; WrappedPtr positions;
size_t size_of_type = 0; size_t size_of_type = 0;
void updateSizeOfType() { size_of_type = getSizeOfIndexType(*positions, size_of_type); } void updateSizeOfType() { size_of_type = getSizeOfIndexType(*positions, size_of_type); }
@ -252,10 +252,10 @@ private:
explicit Dictionary(ColumnPtr column_unique, bool is_shared); explicit Dictionary(ColumnPtr column_unique, bool is_shared);
const ColumnPtr & getColumnUniquePtr() const { return column_unique; } const ColumnPtr & getColumnUniquePtr() const { return column_unique; }
ColumnPtr & getColumnUniquePtr() { return column_unique; } WrappedPtr & getColumnUniquePtr() { return column_unique; }
const IColumnUnique & getColumnUnique() const { return static_cast<const IColumnUnique &>(*column_unique); } const IColumnUnique & getColumnUnique() const { return static_cast<const IColumnUnique &>(*column_unique); }
IColumnUnique & getColumnUnique() { return static_cast<IColumnUnique &>(column_unique->assumeMutableRef()); } IColumnUnique & getColumnUnique() { return static_cast<IColumnUnique &>(*column_unique); }
/// Dictionary may be shared for several mutable columns. /// Dictionary may be shared for several mutable columns.
/// Immutable columns may have the same column unique, which isn't necessarily shared dictionary. /// Immutable columns may have the same column unique, which isn't necessarily shared dictionary.
@ -266,7 +266,7 @@ private:
void compact(ColumnPtr & positions); void compact(ColumnPtr & positions);
private: private:
ColumnPtr column_unique; WrappedPtr column_unique;
bool shared = false; bool shared = false;
void checkColumn(const IColumn & column); void checkColumn(const IColumn & column);

View File

@ -106,16 +106,15 @@ public:
/// Return the column that represents values. /// Return the column that represents values.
IColumn & getNestedColumn() { return nested_column->assumeMutableRef(); } IColumn & getNestedColumn() { return *nested_column; }
const IColumn & getNestedColumn() const { return *nested_column; } const IColumn & getNestedColumn() const { return *nested_column; }
const ColumnPtr & getNestedColumnPtr() const { return nested_column; } const ColumnPtr & getNestedColumnPtr() const { return nested_column; }
/// Return the column that represents the byte map. /// Return the column that represents the byte map.
//ColumnPtr & getNullMapColumnPtr() { return null_map; }
const ColumnPtr & getNullMapColumnPtr() const { return null_map; } const ColumnPtr & getNullMapColumnPtr() const { return null_map; }
ColumnUInt8 & getNullMapColumn() { return static_cast<ColumnUInt8 &>(null_map->assumeMutableRef()); } ColumnUInt8 & getNullMapColumn() { return static_cast<ColumnUInt8 &>(*null_map); }
const ColumnUInt8 & getNullMapColumn() const { return static_cast<const ColumnUInt8 &>(*null_map); } const ColumnUInt8 & getNullMapColumn() const { return static_cast<const ColumnUInt8 &>(*null_map); }
NullMap & getNullMapData() { return getNullMapColumn().getData(); } NullMap & getNullMapData() { return getNullMapColumn().getData(); }
@ -134,8 +133,8 @@ public:
void checkConsistency() const; void checkConsistency() const;
private: private:
ColumnPtr nested_column; WrappedPtr nested_column;
ColumnPtr null_map; WrappedPtr null_map;
template <bool negative> template <bool negative>
void applyNullMapImpl(const ColumnUInt8 & map); void applyNullMapImpl(const ColumnUInt8 & map);

View File

@ -47,6 +47,18 @@ ColumnTuple::ColumnTuple(MutableColumns && mutable_columns)
} }
ColumnTuple::Ptr ColumnTuple::create(const Columns & columns) ColumnTuple::Ptr ColumnTuple::create(const Columns & columns)
{
for (const auto & column : columns)
if (column->isColumnConst())
throw Exception{"ColumnTuple cannot have ColumnConst as its element", ErrorCodes::ILLEGAL_COLUMN};
auto column_tuple = ColumnTuple::create(MutableColumns());
column_tuple->columns.assign(columns.begin(), columns.end());
return column_tuple;
}
ColumnTuple::Ptr ColumnTuple::create(const TupleColumns & columns)
{ {
for (const auto & column : columns) for (const auto & column : columns)
if (column->isColumnConst()) if (column->isColumnConst())
@ -101,7 +113,7 @@ void ColumnTuple::insert(const Field & x)
throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE); throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE);
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
columns[i]->assumeMutableRef().insert(tuple[i]); columns[i]->insert(tuple[i]);
} }
void ColumnTuple::insertFrom(const IColumn & src_, size_t n) void ColumnTuple::insertFrom(const IColumn & src_, size_t n)
@ -113,19 +125,19 @@ void ColumnTuple::insertFrom(const IColumn & src_, size_t n)
throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE); throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE);
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
columns[i]->assumeMutableRef().insertFrom(*src.columns[i], n); columns[i]->insertFrom(*src.columns[i], n);
} }
void ColumnTuple::insertDefault() void ColumnTuple::insertDefault()
{ {
for (auto & column : columns) for (auto & column : columns)
column->assumeMutableRef().insertDefault(); column->insertDefault();
} }
void ColumnTuple::popBack(size_t n) void ColumnTuple::popBack(size_t n)
{ {
for (auto & column : columns) for (auto & column : columns)
column->assumeMutableRef().popBack(n); column->popBack(n);
} }
StringRef ColumnTuple::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const StringRef ColumnTuple::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const
@ -140,7 +152,7 @@ StringRef ColumnTuple::serializeValueIntoArena(size_t n, Arena & arena, char con
const char * ColumnTuple::deserializeAndInsertFromArena(const char * pos) const char * ColumnTuple::deserializeAndInsertFromArena(const char * pos)
{ {
for (auto & column : columns) for (auto & column : columns)
pos = column->assumeMutableRef().deserializeAndInsertFromArena(pos); pos = column->deserializeAndInsertFromArena(pos);
return pos; return pos;
} }
@ -155,7 +167,7 @@ void ColumnTuple::insertRangeFrom(const IColumn & src, size_t start, size_t leng
{ {
const size_t tuple_size = columns.size(); const size_t tuple_size = columns.size();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
columns[i]->assumeMutableRef().insertRangeFrom( columns[i]->insertRangeFrom(
*static_cast<const ColumnTuple &>(src).columns[i], *static_cast<const ColumnTuple &>(src).columns[i],
start, length); start, length);
} }
@ -238,21 +250,19 @@ int ColumnTuple::compareAt(size_t n, size_t m, const IColumn & rhs, int nan_dire
template <bool positive> template <bool positive>
struct ColumnTuple::Less struct ColumnTuple::Less
{ {
ColumnRawPtrs plain_columns; TupleColumns columns;
int nan_direction_hint; int nan_direction_hint;
Less(const Columns & columns, int nan_direction_hint_) Less(const TupleColumns & columns, int nan_direction_hint_)
: nan_direction_hint(nan_direction_hint_) : columns(columns), nan_direction_hint(nan_direction_hint_)
{ {
for (const auto & column : columns)
plain_columns.push_back(column.get());
} }
bool operator() (size_t a, size_t b) const bool operator() (size_t a, size_t b) const
{ {
for (ColumnRawPtrs::const_iterator it = plain_columns.begin(); it != plain_columns.end(); ++it) for (const auto & column : columns)
{ {
int res = (*it)->compareAt(a, b, **it, nan_direction_hint); int res = column->compareAt(a, b, *column, nan_direction_hint);
if (res < 0) if (res < 0)
return positive; return positive;
else if (res > 0) else if (res > 0)
@ -319,7 +329,7 @@ size_t ColumnTuple::allocatedBytes() const
void ColumnTuple::protect() void ColumnTuple::protect()
{ {
for (auto & column : columns) for (auto & column : columns)
column->assumeMutableRef().protect(); column->protect();
} }
void ColumnTuple::getExtremes(Field & min, Field & max) const void ColumnTuple::getExtremes(Field & min, Field & max) const

View File

@ -17,7 +17,8 @@ class ColumnTuple final : public COWPtrHelper<IColumn, ColumnTuple>
private: private:
friend class COWPtrHelper<IColumn, ColumnTuple>; friend class COWPtrHelper<IColumn, ColumnTuple>;
Columns columns; using TupleColumns = std::vector<WrappedPtr>;
TupleColumns columns;
template <bool positive> template <bool positive>
struct Less; struct Less;
@ -31,6 +32,7 @@ public:
*/ */
using Base = COWPtrHelper<IColumn, ColumnTuple>; using Base = COWPtrHelper<IColumn, ColumnTuple>;
static Ptr create(const Columns & columns); static Ptr create(const Columns & columns);
static Ptr create(const TupleColumns & columns);
static Ptr create(Columns && arg) { return create(arg); } static Ptr create(Columns && arg) { return create(arg); }
template <typename Arg, typename = typename std::enable_if<std::is_rvalue_reference<Arg &&>::value>::type> template <typename Arg, typename = typename std::enable_if<std::is_rvalue_reference<Arg &&>::value>::type>
@ -78,9 +80,10 @@ public:
size_t tupleSize() const { return columns.size(); } size_t tupleSize() const { return columns.size(); }
const IColumn & getColumn(size_t idx) const { return *columns[idx]; } const IColumn & getColumn(size_t idx) const { return *columns[idx]; }
IColumn & getColumn(size_t idx) { return columns[idx]->assumeMutableRef(); } IColumn & getColumn(size_t idx) { return *columns[idx]; }
const Columns & getColumns() const { return columns; } const TupleColumns & getColumns() const { return columns; }
Columns getColumnsCopy() const { return {columns.begin(), columns.end()}; }
const ColumnPtr & getColumnPtr(size_t idx) const { return columns[idx]; } const ColumnPtr & getColumnPtr(size_t idx) const { return columns[idx]; }
}; };

View File

@ -80,7 +80,7 @@ public:
bool isNumeric() const override { return column_holder->isNumeric(); } bool isNumeric() const override { return column_holder->isNumeric(); }
size_t byteSize() const override { return column_holder->byteSize(); } size_t byteSize() const override { return column_holder->byteSize(); }
void protect() override { column_holder->assumeMutableRef().protect(); } void protect() override { column_holder->protect(); }
size_t allocatedBytes() const override size_t allocatedBytes() const override
{ {
return column_holder->allocatedBytes() return column_holder->allocatedBytes()
@ -108,14 +108,14 @@ public:
private: private:
ColumnPtr column_holder; IColumn::WrappedPtr column_holder;
bool is_nullable; bool is_nullable;
size_t size_of_value_if_fixed = 0; size_t size_of_value_if_fixed = 0;
ReverseIndex<UInt64, ColumnType> index; ReverseIndex<UInt64, ColumnType> index;
/// For DataTypeNullable, stores null map. /// For DataTypeNullable, stores null map.
ColumnPtr nested_null_mask; IColumn::WrappedPtr nested_null_mask;
ColumnPtr nested_column_nullable; IColumn::WrappedPtr nested_column_nullable;
class IncrementalHash class IncrementalHash
{ {
@ -138,7 +138,7 @@ private:
static size_t numSpecialValues(bool is_nullable) { return is_nullable ? 2 : 1; } static size_t numSpecialValues(bool is_nullable) { return is_nullable ? 2 : 1; }
size_t numSpecialValues() const { return numSpecialValues(is_nullable); } size_t numSpecialValues() const { return numSpecialValues(is_nullable); }
ColumnType * getRawColumnPtr() { return static_cast<ColumnType *>(column_holder->assumeMutable().get()); } ColumnType * getRawColumnPtr() { return static_cast<ColumnType *>(column_holder.get()); }
const ColumnType * getRawColumnPtr() const { return static_cast<const ColumnType *>(column_holder.get()); } const ColumnType * getRawColumnPtr() const { return static_cast<const ColumnType *>(column_holder.get()); }
template <typename IndexType> template <typename IndexType>
@ -230,10 +230,7 @@ void ColumnUnique<ColumnType>::updateNullMask()
size_t size = getRawColumnPtr()->size(); size_t size = getRawColumnPtr()->size();
if (nested_null_mask->size() != size) if (nested_null_mask->size() != size)
{ static_cast<ColumnUInt8 &>(*nested_null_mask).getData().resize_fill(size);
IColumn & null_mask = nested_null_mask->assumeMutableRef();
static_cast<ColumnUInt8 &>(null_mask).getData().resize_fill(size);
}
} }
} }

View File

@ -259,7 +259,7 @@ public:
/// If the column contains subcolumns (such as Array, Nullable, etc), do callback on them. /// If the column contains subcolumns (such as Array, Nullable, etc), do callback on them.
/// Shallow: doesn't do recursive calls; don't do call for itself. /// Shallow: doesn't do recursive calls; don't do call for itself.
using ColumnCallback = std::function<void(Ptr&)>; using ColumnCallback = std::function<void(WrappedPtr&)>;
virtual void forEachSubcolumn(ColumnCallback) {} virtual void forEachSubcolumn(ColumnCallback) {}
/// Columns have equal structure. /// Columns have equal structure.
@ -272,8 +272,8 @@ public:
MutablePtr mutate() const && MutablePtr mutate() const &&
{ {
MutablePtr res = COWPtr<IColumn>::mutate(); MutablePtr res = shallowMutate();
res->forEachSubcolumn([](Ptr & subcolumn) { subcolumn = (*std::move(subcolumn)).mutate(); }); res->forEachSubcolumn([](WrappedPtr & subcolumn) { subcolumn = std::move(*subcolumn).mutate(); });
return res; return res;
} }

View File

@ -50,7 +50,7 @@
/// Change value of x. /// Change value of x.
{ {
/// Creating mutable ptr. It can clone an object under the hood if it was shared. /// Creating mutable ptr. It can clone an object under the hood if it was shared.
Column::MutablePtr mutate_x = x->mutate(); Column::MutablePtr mutate_x = std::move(*x).mutate();
/// Using non-const methods of an object. /// Using non-const methods of an object.
mutate_x->set(2); mutate_x->set(2);
/// Assigning pointer 'x' to mutated object. /// Assigning pointer 'x' to mutated object.
@ -175,7 +175,8 @@ public:
Ptr getPtr() const { return static_cast<Ptr>(derived()); } Ptr getPtr() const { return static_cast<Ptr>(derived()); }
MutablePtr getPtr() { return static_cast<MutablePtr>(derived()); } MutablePtr getPtr() { return static_cast<MutablePtr>(derived()); }
MutablePtr mutate() const protected:
MutablePtr shallowMutate() const
{ {
if (this->use_count() > 1) if (this->use_count() > 1)
return derived()->clone(); return derived()->clone();
@ -183,6 +184,12 @@ public:
return assumeMutable(); return assumeMutable();
} }
public:
MutablePtr mutate() const &&
{
return shallowMutate();
}
MutablePtr assumeMutable() const MutablePtr assumeMutable() const
{ {
return const_cast<COWPtr*>(this)->getPtr(); return const_cast<COWPtr*>(this)->getPtr();
@ -192,6 +199,56 @@ public:
{ {
return const_cast<Derived &>(*derived()); return const_cast<Derived &>(*derived());
} }
protected:
/// It works as immutable_ptr if it is const and as mutable_ptr if it is non const.
template <typename T>
class chameleon_ptr
{
private:
immutable_ptr<T> value;
public:
template <typename... Args>
chameleon_ptr(Args &&... args) : value(std::forward<Args>(args)...) {}
template <typename U>
chameleon_ptr(std::initializer_list<U> && arg) : value(std::forward<std::initializer_list<U>>(arg)) {}
const T * get() const { return value.get(); }
T * get() { return value->assumeMutable().get(); }
const T * operator->() const { return get(); }
T * operator->() { return get(); }
const T & operator*() const { return *value; }
T & operator*() { return value->assumeMutableRef(); }
operator const immutable_ptr<T> & () const { return value; }
operator immutable_ptr<T> & () { return value; }
operator bool() const { return value != nullptr; }
bool operator! () const { return value == nullptr; }
bool operator== (const chameleon_ptr & rhs) const { return value == rhs.value; }
bool operator!= (const chameleon_ptr & rhs) const { return value != rhs.value; }
};
public:
/** Use this type in class members for compositions.
*
* NOTE:
* For classes with WrappedPtr members,
* you must reimplement 'mutate' method, so it will call 'mutate' of all subobjects (do deep mutate).
* It will guarantee, that mutable object have all subobjects unshared.
*
* NOTE:
* If you override 'mutate' method in inherited classes, don't forget to make it virtual in base class or to make it call a virtual method.
* (COWPtr itself doesn't force any methods to be virtual).
*
* See example in "cow_compositions.cpp".
*/
using WrappedPtr = chameleon_ptr<Derived>;
}; };
@ -217,6 +274,8 @@ public:
* IColumn * IColumn
* CowPtr<IColumn> * CowPtr<IColumn>
* boost::intrusive_ref_counter<IColumn> * boost::intrusive_ref_counter<IColumn>
*
* See example in "cow_columns.cpp".
*/ */
template <typename Base, typename Derived> template <typename Base, typename Derived>
class COWPtrHelper : public Base class COWPtrHelper : public Base
@ -236,25 +295,7 @@ public:
static MutablePtr create(std::initializer_list<T> && arg) { return create(std::forward<std::initializer_list<T>>(arg)); } static MutablePtr create(std::initializer_list<T> && arg) { return create(std::forward<std::initializer_list<T>>(arg)); }
typename Base::MutablePtr clone() const override { return typename Base::MutablePtr(new Derived(*derived())); } typename Base::MutablePtr clone() const override { return typename Base::MutablePtr(new Derived(*derived())); }
protected:
MutablePtr shallowMutate() const { return MutablePtr(static_cast<Derived *>(Base::shallowMutate().get())); }
}; };
/** Compositions.
*
* Sometimes your objects contain another objects, and you have tree-like structure.
* And you want non-const methods of your object to also modify your subobjects.
*
* There are the following possible solutions:
*
* 1. Store subobjects as immutable ptrs. Call mutate method of subobjects inside non-const methods of your objects; modify them and assign back.
* Drawback: additional checks inside methods: CPU overhead on atomic ops.
*
* 2. Store subobjects as mutable ptrs. Subobjects cannot be shared in another objects.
* Drawback: it's not possible to share subobjects.
*
* 3. Store subobjects as immutable ptrs. Implement copy-constructor to do shallow copy.
* But reimplement 'mutate' method, so it will call 'mutate' of all subobjects (do deep mutate).
* It will guarantee, that mutable object have all subobjects unshared.
* From non-const method, you can modify subobjects with 'assumeMutableRef' method.
* Drawback: it's more complex than other solutions.
*/

View File

@ -36,6 +36,11 @@ struct HashMethodOneNumber
vec = key_columns[0]->getRawData().data; vec = key_columns[0]->getRawData().data;
} }
HashMethodOneNumber(const IColumn * column)
{
vec = column->getRawData().data;
}
/// Creates context. Method is called once and result context is used in all threads. /// Creates context. Method is called once and result context is used in all threads.
using Base::createContext; /// (const HashMethodContext::Settings &) -> HashMethodContextPtr using Base::createContext; /// (const HashMethodContext::Settings &) -> HashMethodContextPtr

View File

@ -420,6 +420,7 @@ namespace ErrorCodes
extern const int NO_COMMON_COLUMNS_WITH_PROTOBUF_SCHEMA = 443; extern const int NO_COMMON_COLUMNS_WITH_PROTOBUF_SCHEMA = 443;
extern const int UNKNOWN_PROTOBUF_FORMAT = 444; extern const int UNKNOWN_PROTOBUF_FORMAT = 444;
extern const int CANNOT_MPROTECT = 445; extern const int CANNOT_MPROTECT = 445;
extern const int FUNCTION_NOT_ALLOWED = 446;
extern const int KEEPER_EXCEPTION = 999; extern const int KEEPER_EXCEPTION = 999;
extern const int POCO_EXCEPTION = 1000; extern const int POCO_EXCEPTION = 1000;

View File

@ -1,17 +1,14 @@
#include "Exception.h"
#include <string.h> #include <string.h>
#include <cxxabi.h> #include <cxxabi.h>
#include <Poco/String.h> #include <Poco/String.h>
#include <common/logger_useful.h> #include <common/logger_useful.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <IO/Operators.h> #include <IO/Operators.h>
#include <IO/ReadBufferFromString.h> #include <IO/ReadBufferFromString.h>
#include <Common/Exception.h>
#include <common/demangle.h> #include <common/demangle.h>
#include <Common/config_version.h>
namespace DB namespace DB
{ {
@ -24,6 +21,10 @@ namespace ErrorCodes
extern const int CANNOT_TRUNCATE_FILE; extern const int CANNOT_TRUNCATE_FILE;
} }
const char * getVersion()
{
return VERSION_STRING;
}
std::string errnoToString(int code, int e) std::string errnoToString(int code, int e)
{ {
@ -81,13 +82,13 @@ std::string getCurrentExceptionMessage(bool with_stacktrace, bool check_embedded
} }
catch (const Exception & e) catch (const Exception & e)
{ {
stream << getExceptionMessage(e, with_stacktrace, check_embedded_stacktrace); stream << "(version " << getVersion() << ") " << getExceptionMessage(e, with_stacktrace, check_embedded_stacktrace);
} }
catch (const Poco::Exception & e) catch (const Poco::Exception & e)
{ {
try try
{ {
stream << "Poco::Exception. Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code() stream << "(version " << getVersion() << ") " << "Poco::Exception. Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code()
<< ", e.displayText() = " << e.displayText(); << ", e.displayText() = " << e.displayText();
} }
catch (...) {} catch (...) {}
@ -102,7 +103,7 @@ std::string getCurrentExceptionMessage(bool with_stacktrace, bool check_embedded
if (status) if (status)
name += " (demangling status: " + toString(status) + ")"; name += " (demangling status: " + toString(status) + ")";
stream << "std::exception. Code: " << ErrorCodes::STD_EXCEPTION << ", type: " << name << ", e.what() = " << e.what(); stream << "(version " << getVersion() << ") " << "std::exception. Code: " << ErrorCodes::STD_EXCEPTION << ", type: " << name << ", e.what() = " << e.what();
} }
catch (...) {} catch (...) {}
} }
@ -116,7 +117,7 @@ std::string getCurrentExceptionMessage(bool with_stacktrace, bool check_embedded
if (status) if (status)
name += " (demangling status: " + toString(status) + ")"; name += " (demangling status: " + toString(status) + ")";
stream << "Unknown exception. Code: " << ErrorCodes::UNKNOWN_EXCEPTION << ", type: " << name; stream << "(version " << getVersion() << ") " << "Unknown exception. Code: " << ErrorCodes::UNKNOWN_EXCEPTION << ", type: " << name;
} }
catch (...) {} catch (...) {}
} }

View File

@ -82,5 +82,8 @@ target_link_libraries (allocator PRIVATE clickhouse_common_io)
add_executable (cow_columns cow_columns.cpp) add_executable (cow_columns cow_columns.cpp)
target_link_libraries (cow_columns PRIVATE clickhouse_common_io) target_link_libraries (cow_columns PRIVATE clickhouse_common_io)
add_executable (cow_compositions cow_compositions.cpp)
target_link_libraries (cow_compositions PRIVATE clickhouse_common_io)
add_executable (stopwatch stopwatch.cpp) add_executable (stopwatch stopwatch.cpp)
target_link_libraries (stopwatch PRIVATE clickhouse_common_io) target_link_libraries (stopwatch PRIVATE clickhouse_common_io)

View File

@ -53,7 +53,7 @@ int main(int, char **)
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n"; std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
{ {
MutableColumnPtr mut = y->mutate(); MutableColumnPtr mut = std::move(*y).mutate();
mut->set(2); mut->set(2);
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n"; std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n";
@ -72,7 +72,7 @@ int main(int, char **)
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n"; std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
{ {
MutableColumnPtr mut = y->mutate(); MutableColumnPtr mut = std::move(*y).mutate();
mut->set(3); mut->set(3);
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n"; std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n";

View File

@ -0,0 +1,107 @@
#include <Common/COWPtr.h>
#include <iostream>
class IColumn : public COWPtr<IColumn>
{
private:
friend class COWPtr<IColumn>;
virtual MutablePtr clone() const = 0;
virtual MutablePtr deepMutate() const { return shallowMutate(); }
public:
IColumn() = default;
IColumn(const IColumn &) = default;
virtual ~IColumn() = default;
virtual int get() const = 0;
virtual void set(int value) = 0;
MutablePtr mutate() const && { return deepMutate(); }
};
using ColumnPtr = IColumn::Ptr;
using MutableColumnPtr = IColumn::MutablePtr;
class ConcreteColumn : public COWPtrHelper<IColumn, ConcreteColumn>
{
private:
friend class COWPtrHelper<IColumn, ConcreteColumn>;
int data;
ConcreteColumn(int data) : data(data) {}
ConcreteColumn(const ConcreteColumn &) = default;
public:
int get() const override { return data; }
void set(int value) override { data = value; }
};
class ColumnComposition : public COWPtrHelper<IColumn, ColumnComposition>
{
private:
friend class COWPtrHelper<IColumn, ColumnComposition>;
ConcreteColumn::WrappedPtr wrapped;
ColumnComposition(int data) : wrapped(ConcreteColumn::create(data)) {}
ColumnComposition(const ColumnComposition &) = default;
IColumn::MutablePtr deepMutate() const override
{
std::cerr << "Mutating\n";
auto res = shallowMutate();
res->wrapped = std::move(*wrapped).mutate();
return res;
}
public:
int get() const override { return wrapped->get(); }
void set(int value) override { wrapped->set(value); }
};
int main(int, char **)
{
ColumnPtr x = ColumnComposition::create(1);
ColumnPtr y = x;
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
{
MutableColumnPtr mut = std::move(*y).mutate();
mut->set(2);
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n";
std::cerr << "addresses: " << x.get() << ", " << y.get() << ", " << mut.get() << "\n";
y = std::move(mut);
}
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
x = ColumnComposition::create(0);
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
{
MutableColumnPtr mut = std::move(*y).mutate();
mut->set(3);
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n";
std::cerr << "addresses: " << x.get() << ", " << y.get() << ", " << mut.get() << "\n";
y = std::move(mut);
}
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
return 0;
}

View File

@ -305,7 +305,9 @@ struct Settings
M(SettingBool, allow_experimental_cross_to_join_conversion, true, "Convert CROSS JOIN to INNER JOIN if possible") \ M(SettingBool, allow_experimental_cross_to_join_conversion, true, "Convert CROSS JOIN to INNER JOIN if possible") \
M(SettingBool, cancel_http_readonly_queries_on_client_close, false, "Cancel HTTP readonly queries when a client closes the connection without waiting for response.") \ M(SettingBool, cancel_http_readonly_queries_on_client_close, false, "Cancel HTTP readonly queries when a client closes the connection without waiting for response.") \
M(SettingBool, external_table_functions_use_nulls, true, "If it is set to true, external table functions will implicitly use Nullable type if needed. Otherwise NULLs will be substituted with default values. Currently supported only for 'mysql' table function.") \ M(SettingBool, external_table_functions_use_nulls, true, "If it is set to true, external table functions will implicitly use Nullable type if needed. Otherwise NULLs will be substituted with default values. Currently supported only for 'mysql' table function.") \
M(SettingBool, allow_experimental_data_skipping_indices, false, "If it is set to true, data skipping indices can be used in CREATE TABLE/ALTER TABLE queries.")\ M(SettingBool, allow_experimental_data_skipping_indices, false, "If it is set to true, data skipping indices can be used in CREATE TABLE/ALTER TABLE queries.") \
\
M(SettingBool, allow_hyperscan, true, "Allow functions that use Hyperscan library. Disable to avoid potentially long compilation times and excessive resource usage.") \
#define DECLARE(TYPE, NAME, DEFAULT, DESCRIPTION) \ #define DECLARE(TYPE, NAME, DEFAULT, DESCRIPTION) \
TYPE NAME {DEFAULT}; TYPE NAME {DEFAULT};

View File

@ -80,9 +80,9 @@ std::ostream & operator<<(std::ostream & stream, const IColumn & what)
stream << "{"; stream << "{";
for (size_t i = 0; i < what.size(); ++i) for (size_t i = 0; i < what.size(); ++i)
{ {
stream << applyVisitor(FieldVisitorDump(), what[i]);
if (i) if (i)
stream << ", "; stream << ", ";
stream << applyVisitor(FieldVisitorDump(), what[i]);
} }
stream << "}"; stream << "}";

View File

@ -60,12 +60,11 @@ Block ColumnGathererStream::readImpl()
if (!source_to_fully_copy && row_sources_buf.eof()) if (!source_to_fully_copy && row_sources_buf.eof())
return Block(); return Block();
MutableColumnPtr output_column = column.column->cloneEmpty();
output_block = Block{column.cloneEmpty()}; output_block = Block{column.cloneEmpty()};
MutableColumnPtr output_column = output_block.getByPosition(0).column->assumeMutable();
output_column->gather(*this); output_column->gather(*this);
if (!output_column->empty()) if (!output_column->empty())
output_block.getByPosition(0).column = std::move(output_column); output_block.getByPosition(0).column = std::move(output_column);
return output_block; return output_block;
} }

View File

@ -69,7 +69,7 @@ ColumnPtr recursiveRemoveLowCardinality(const ColumnPtr & column)
if (const auto * column_tuple = typeid_cast<const ColumnTuple *>(column.get())) if (const auto * column_tuple = typeid_cast<const ColumnTuple *>(column.get()))
{ {
Columns columns = column_tuple->getColumns(); auto columns = column_tuple->getColumns();
for (auto & element : columns) for (auto & element : columns)
element = recursiveRemoveLowCardinality(element); element = recursiveRemoveLowCardinality(element);
return ColumnTuple::create(columns); return ColumnTuple::create(columns);
@ -142,7 +142,7 @@ ColumnPtr recursiveLowCardinalityConversion(const ColumnPtr & column, const Data
throw Exception("Unexpected column " + column->getName() + " for type " + from_type->getName(), throw Exception("Unexpected column " + column->getName() + " for type " + from_type->getName(),
ErrorCodes::ILLEGAL_COLUMN); ErrorCodes::ILLEGAL_COLUMN);
Columns columns = column_tuple->getColumns(); auto columns = column_tuple->getColumns();
auto & from_elements = from_tuple_type->getElements(); auto & from_elements = from_tuple_type->getElements();
auto & to_elements = to_tuple_type->getElements(); auto & to_elements = to_tuple_type->getElements();

View File

@ -101,7 +101,7 @@ Block flatten(const Block & block)
const ColumnPtr & column_offsets = column_array->getOffsetsPtr(); const ColumnPtr & column_offsets = column_array->getOffsetsPtr();
const ColumnTuple & column_tuple = typeid_cast<const ColumnTuple &>(column_array->getData()); const ColumnTuple & column_tuple = typeid_cast<const ColumnTuple &>(column_array->getData());
const Columns & element_columns = column_tuple.getColumns(); const auto & element_columns = column_tuple.getColumns();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
{ {

View File

@ -33,7 +33,7 @@ const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * co
Columns convertConstTupleToConstantElements(const ColumnConst & column) Columns convertConstTupleToConstantElements(const ColumnConst & column)
{ {
const ColumnTuple & src_tuple = static_cast<const ColumnTuple &>(column.getDataColumn()); const ColumnTuple & src_tuple = static_cast<const ColumnTuple &>(column.getDataColumn());
const Columns & src_tuple_columns = src_tuple.getColumns(); const auto & src_tuple_columns = src_tuple.getColumns();
size_t tuple_size = src_tuple_columns.size(); size_t tuple_size = src_tuple_columns.size();
size_t rows = column.size(); size_t rows = column.size();

View File

@ -932,12 +932,12 @@ private:
if (x_const) if (x_const)
x_columns = convertConstTupleToConstantElements(*x_const); x_columns = convertConstTupleToConstantElements(*x_const);
else else
x_columns = static_cast<const ColumnTuple &>(*c0.column).getColumns(); x_columns = static_cast<const ColumnTuple &>(*c0.column).getColumnsCopy();
if (y_const) if (y_const)
y_columns = convertConstTupleToConstantElements(*y_const); y_columns = convertConstTupleToConstantElements(*y_const);
else else
y_columns = static_cast<const ColumnTuple &>(*c1.column).getColumns(); y_columns = static_cast<const ColumnTuple &>(*c1.column).getColumnsCopy();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
{ {

View File

@ -167,7 +167,7 @@ private:
if (checkColumn<ColumnTuple>(key_col.get())) if (checkColumn<ColumnTuple>(key_col.get()))
{ {
const auto & key_columns = static_cast<const ColumnTuple &>(*key_col).getColumns(); const auto & key_columns = static_cast<const ColumnTuple &>(*key_col).getColumnsCopy();
const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements(); const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements();
auto out = ColumnUInt8::create(key_col_with_type.column->size()); auto out = ColumnUInt8::create(key_col_with_type.column->size());
@ -353,7 +353,7 @@ private:
if (checkColumn<ColumnTuple>(key_col.get())) if (checkColumn<ColumnTuple>(key_col.get()))
{ {
const auto & key_columns = static_cast<const ColumnTuple &>(*key_col).getColumns(); const auto & key_columns = static_cast<const ColumnTuple &>(*key_col).getColumnsCopy();
const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements(); const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements();
auto out = ColumnString::create(); auto out = ColumnString::create();
@ -580,7 +580,7 @@ private:
/// Functions in external dictionaries only support full-value (not constant) columns with keys. /// Functions in external dictionaries only support full-value (not constant) columns with keys.
ColumnPtr key_col = key_col_with_type.column->convertToFullColumnIfConst(); ColumnPtr key_col = key_col_with_type.column->convertToFullColumnIfConst();
const auto & key_columns = typeid_cast<const ColumnTuple &>(*key_col).getColumns(); const auto & key_columns = typeid_cast<const ColumnTuple &>(*key_col).getColumnsCopy();
const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements(); const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements();
auto out = ColumnString::create(); auto out = ColumnString::create();
@ -815,7 +815,7 @@ private:
if (checkColumn<ColumnTuple>(key_col.get())) if (checkColumn<ColumnTuple>(key_col.get()))
{ {
const auto & key_columns = static_cast<const ColumnTuple &>(*key_col).getColumns(); const auto & key_columns = static_cast<const ColumnTuple &>(*key_col).getColumnsCopy();
const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements(); const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements();
auto out = ColumnVector<Type>::create(key_columns.front()->size()); auto out = ColumnVector<Type>::create(key_columns.front()->size());
@ -1077,7 +1077,7 @@ private:
/// Functions in external dictionaries only support full-value (not constant) columns with keys. /// Functions in external dictionaries only support full-value (not constant) columns with keys.
ColumnPtr key_col = key_col_with_type.column->convertToFullColumnIfConst(); ColumnPtr key_col = key_col_with_type.column->convertToFullColumnIfConst();
const auto & key_columns = typeid_cast<const ColumnTuple &>(*key_col).getColumns(); const auto & key_columns = typeid_cast<const ColumnTuple &>(*key_col).getColumnsCopy();
const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements(); const auto & key_types = static_cast<const DataTypeTuple &>(*key_col_with_type.type).getElements();
/// @todo detect when all key columns are constant /// @todo detect when all key columns are constant

View File

@ -159,7 +159,7 @@ public:
ErrorCodes::ILLEGAL_COLUMN); ErrorCodes::ILLEGAL_COLUMN);
} }
const Columns & tuple_columns = tuple_col->getColumns(); const auto & tuple_columns = tuple_col->getColumns();
const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(*block.getByPosition(arguments[0]).type).getElements(); const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(*block.getByPosition(arguments[0]).type).getElements();
bool use_float64 = WhichDataType(tuple_types[0]).isFloat64() || WhichDataType(tuple_types[1]).isFloat64(); bool use_float64 = WhichDataType(tuple_types[0]).isFloat64() || WhichDataType(tuple_types[1]).isFloat64();

View File

@ -818,7 +818,7 @@ private:
/// Flattening of tuples. /// Flattening of tuples.
if (const ColumnTuple * tuple = typeid_cast<const ColumnTuple *>(column)) if (const ColumnTuple * tuple = typeid_cast<const ColumnTuple *>(column))
{ {
const Columns & tuple_columns = tuple->getColumns(); const auto & tuple_columns = tuple->getColumns();
const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(*type).getElements(); const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(*type).getElements();
size_t tuple_size = tuple_columns.size(); size_t tuple_size = tuple_columns.size();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
@ -826,7 +826,7 @@ private:
} }
else if (const ColumnTuple * tuple_const = checkAndGetColumnConstData<ColumnTuple>(column)) else if (const ColumnTuple * tuple_const = checkAndGetColumnConstData<ColumnTuple>(column))
{ {
const Columns & tuple_columns = tuple_const->getColumns(); const auto & tuple_columns = tuple_const->getColumns();
const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(*type).getElements(); const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(*type).getElements();
size_t tuple_size = tuple_columns.size(); size_t tuple_size = tuple_columns.size();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)

View File

@ -0,0 +1,944 @@
#include "FunctionsStringRegex.h"
#include "FunctionsStringSearch.h"
#include <Columns/ColumnFixedString.h>
#include <DataTypes/DataTypeFixedString.h>
#include <Functions/FunctionFactory.h>
#include <Functions/Regexps.h>
#include <IO/WriteHelpers.h>
#include <re2/re2.h>
#include <re2/stringpiece.h>
#include <Poco/UTF8String.h>
#include <Common/Volnitsky.h>
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <Common/config.h>
#if USE_HYPERSCAN
# if __has_include(<hs/hs.h>)
# include <hs/hs.h>
# else
# include <hs.h>
# endif
#endif
#if USE_RE2_ST
# include <re2_st/re2.h> // Y_IGNORE
#else
# define re2_st re2
#endif
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
extern const int ILLEGAL_COLUMN;
extern const int TOO_MANY_BYTES;
extern const int NOT_IMPLEMENTED;
}
/// Is the LIKE expression reduced to finding a substring in a string?
inline bool likePatternIsStrstr(const String & pattern, String & res)
{
res = "";
if (pattern.size() < 2 || pattern.front() != '%' || pattern.back() != '%')
return false;
res.reserve(pattern.size() * 2);
const char * pos = pattern.data();
const char * end = pos + pattern.size();
++pos;
--end;
while (pos < end)
{
switch (*pos)
{
case '%':
case '_':
return false;
case '\\':
++pos;
if (pos == end)
return false;
else
res += *pos;
break;
default:
res += *pos;
break;
}
++pos;
}
return true;
}
/** 'like' - if true, treat pattern as SQL LIKE; if false - treat pattern as re2 regexp.
* NOTE: We want to run regexp search for whole block by one call (as implemented in function 'position')
* but for that, regexp engine must support \0 bytes and their interpretation as string boundaries.
*/
template <bool like, bool revert = false>
struct MatchImpl
{
using ResultType = UInt8;
static void vector_constant(
const ColumnString::Chars & data, const ColumnString::Offsets & offsets, const std::string & pattern, PaddedPODArray<UInt8> & res)
{
if (offsets.empty())
return;
String strstr_pattern;
/// A simple case where the LIKE expression reduces to finding a substring in a string
if (like && likePatternIsStrstr(pattern, strstr_pattern))
{
const UInt8 * begin = data.data();
const UInt8 * pos = begin;
const UInt8 * end = pos + data.size();
/// The current index in the array of strings.
size_t i = 0;
/// TODO You need to make that `searcher` is common to all the calls of the function.
Volnitsky searcher(strstr_pattern.data(), strstr_pattern.size(), end - pos);
/// We will search for the next occurrence in all rows at once.
while (pos < end && end != (pos = searcher.search(pos, end - pos)))
{
/// Let's determine which index it refers to.
while (begin + offsets[i] <= pos)
{
res[i] = revert;
++i;
}
/// We check that the entry does not pass through the boundaries of strings.
if (pos + strstr_pattern.size() < begin + offsets[i])
res[i] = !revert;
else
res[i] = revert;
pos = begin + offsets[i];
++i;
}
/// Tail, in which there can be no substring.
if (i < res.size())
memset(&res[i], revert, (res.size() - i) * sizeof(res[0]));
}
else
{
size_t size = offsets.size();
const auto & regexp = Regexps::get<like, true>(pattern);
std::string required_substring;
bool is_trivial;
bool required_substring_is_prefix; /// for `anchored` execution of the regexp.
regexp->getAnalyzeResult(required_substring, is_trivial, required_substring_is_prefix);
if (required_substring.empty())
{
if (!regexp->getRE2()) /// An empty regexp. Always matches.
{
if (size)
memset(res.data(), 1, size * sizeof(res[0]));
}
else
{
size_t prev_offset = 0;
for (size_t i = 0; i < size; ++i)
{
res[i] = revert
^ regexp->getRE2()->Match(
re2_st::StringPiece(reinterpret_cast<const char *>(&data[prev_offset]), offsets[i] - prev_offset - 1),
0,
offsets[i] - prev_offset - 1,
re2_st::RE2::UNANCHORED,
nullptr,
0);
prev_offset = offsets[i];
}
}
}
else
{
/// NOTE This almost matches with the case of LikePatternIsStrstr.
const UInt8 * begin = data.data();
const UInt8 * pos = begin;
const UInt8 * end = pos + data.size();
/// The current index in the array of strings.
size_t i = 0;
Volnitsky searcher(required_substring.data(), required_substring.size(), end - pos);
/// We will search for the next occurrence in all rows at once.
while (pos < end && end != (pos = searcher.search(pos, end - pos)))
{
/// Determine which index it refers to.
while (begin + offsets[i] <= pos)
{
res[i] = revert;
++i;
}
/// We check that the entry does not pass through the boundaries of strings.
if (pos + strstr_pattern.size() < begin + offsets[i])
{
/// And if it does not, if necessary, we check the regexp.
if (is_trivial)
res[i] = !revert;
else
{
const char * str_data = reinterpret_cast<const char *>(&data[offsets[i - 1]]);
size_t str_size = offsets[i] - offsets[i - 1] - 1;
/** Even in the case of `required_substring_is_prefix` use UNANCHORED check for regexp,
* so that it can match when `required_substring` occurs into the string several times,
* and at the first occurrence, the regexp is not a match.
*/
if (required_substring_is_prefix)
res[i] = revert
^ regexp->getRE2()->Match(
re2_st::StringPiece(str_data, str_size),
reinterpret_cast<const char *>(pos) - str_data,
str_size,
re2_st::RE2::UNANCHORED,
nullptr,
0);
else
res[i] = revert
^ regexp->getRE2()->Match(
re2_st::StringPiece(str_data, str_size), 0, str_size, re2_st::RE2::UNANCHORED, nullptr, 0);
}
}
else
res[i] = revert;
pos = begin + offsets[i];
++i;
}
if (i < res.size())
memset(&res[i], revert, (res.size() - i) * sizeof(res[0]));
}
}
}
static void constant_constant(const std::string & data, const std::string & pattern, UInt8 & res)
{
const auto & regexp = Regexps::get<like, true>(pattern);
res = revert ^ regexp->match(data);
}
template <typename... Args>
static void vector_vector(Args &&...)
{
throw Exception("Functions 'like' and 'match' don't support non-constant needle argument", ErrorCodes::ILLEGAL_COLUMN);
}
/// Search different needles in single haystack.
template <typename... Args>
static void constant_vector(Args &&...)
{
throw Exception("Functions 'like' and 'match' don't support non-constant needle argument", ErrorCodes::ILLEGAL_COLUMN);
}
};
template <typename Type, bool FindAny, bool FindAnyIndex, bool MultiSearchDistance>
struct MultiMatchAnyImpl
{
static_assert(static_cast<int>(FindAny) + static_cast<int>(FindAnyIndex) == 1);
using ResultType = Type;
static constexpr bool is_using_hyperscan = true;
static void vector_constant(
const ColumnString::Chars & haystack_data,
const ColumnString::Offsets & haystack_offsets,
const std::vector<StringRef> & needles,
PaddedPODArray<Type> & res)
{
vector_constant(haystack_data, haystack_offsets, needles, res, std::nullopt);
}
static void vector_constant(
const ColumnString::Chars & haystack_data,
const ColumnString::Offsets & haystack_offsets,
const std::vector<StringRef> & needles,
PaddedPODArray<Type> & res,
[[maybe_unused]] std::optional<UInt32> edit_distance)
{
(void)FindAny;
(void)FindAnyIndex;
#if USE_HYPERSCAN
const auto & hyperscan_regex = MultiRegexps::get<FindAnyIndex, MultiSearchDistance>(needles, edit_distance);
hs_scratch_t * scratch = nullptr;
hs_error_t err = hs_alloc_scratch(hyperscan_regex->get(), &scratch);
if (err != HS_SUCCESS)
throw Exception("Could not allocate scratch space for hyperscan", ErrorCodes::CANNOT_ALLOCATE_MEMORY);
MultiRegexps::ScratchPtr smart_scratch(scratch);
auto on_match = []([[maybe_unused]] unsigned int id,
unsigned long long /* from */,
unsigned long long /* to */,
unsigned int /* flags */,
void * context) -> int
{
if constexpr (FindAnyIndex)
*reinterpret_cast<Type *>(context) = id;
else if constexpr (FindAny)
*reinterpret_cast<Type *>(context) = 1;
return 0;
};
const size_t haystack_offsets_size = haystack_offsets.size();
UInt64 offset = 0;
for (size_t i = 0; i < haystack_offsets_size; ++i)
{
UInt64 length = haystack_offsets[i] - offset - 1;
if (length > std::numeric_limits<UInt32>::max())
throw Exception("Too long string to search", ErrorCodes::TOO_MANY_BYTES);
res[i] = 0;
hs_scan(
hyperscan_regex->get(),
reinterpret_cast<const char *>(haystack_data.data()) + offset,
length,
0,
smart_scratch.get(),
on_match,
&res[i]);
offset = haystack_offsets[i];
}
#else
/// Fallback if do not use hyperscan
if constexpr (MultiSearchDistance)
throw Exception(
"Edit distance multi-search is not implemented when hyperscan is off (is it Intel processor?)",
ErrorCodes::NOT_IMPLEMENTED);
PaddedPODArray<UInt8> accum(res.size());
memset(res.data(), 0, res.size() * sizeof(res.front()));
memset(accum.data(), 0, accum.size());
for (size_t j = 0; j < needles.size(); ++j)
{
MatchImpl<false, false>::vector_constant(haystack_data, haystack_offsets, needles[j].toString(), accum);
for (size_t i = 0; i < res.size(); ++i)
{
if constexpr (FindAny)
res[i] |= accum[i];
else if (FindAnyIndex && accum[i])
res[i] = j + 1;
}
}
#endif // USE_HYPERSCAN
}
};
struct ExtractImpl
{
static void vector(
const ColumnString::Chars & data,
const ColumnString::Offsets & offsets,
const std::string & pattern,
ColumnString::Chars & res_data,
ColumnString::Offsets & res_offsets)
{
res_data.reserve(data.size() / 5);
res_offsets.resize(offsets.size());
const auto & regexp = Regexps::get<false, false>(pattern);
unsigned capture = regexp->getNumberOfSubpatterns() > 0 ? 1 : 0;
OptimizedRegularExpression::MatchVec matches;
matches.reserve(capture + 1);
size_t prev_offset = 0;
size_t res_offset = 0;
for (size_t i = 0; i < offsets.size(); ++i)
{
size_t cur_offset = offsets[i];
unsigned count
= regexp->match(reinterpret_cast<const char *>(&data[prev_offset]), cur_offset - prev_offset - 1, matches, capture + 1);
if (count > capture && matches[capture].offset != std::string::npos)
{
const auto & match = matches[capture];
res_data.resize(res_offset + match.length + 1);
memcpySmallAllowReadWriteOverflow15(&res_data[res_offset], &data[prev_offset + match.offset], match.length);
res_offset += match.length;
}
else
{
res_data.resize(res_offset + 1);
}
res_data[res_offset] = 0;
++res_offset;
res_offsets[i] = res_offset;
prev_offset = cur_offset;
}
}
};
/** Replace all matches of regexp 'needle' to string 'replacement'. 'needle' and 'replacement' are constants.
* 'replacement' could contain substitutions, for example: '\2-\3-\1'
*/
template <bool replace_one = false>
struct ReplaceRegexpImpl
{
/// Sequence of instructions, describing how to get resulting string.
/// Each element is either:
/// - substitution (in that case first element of pair is their number and second element is empty)
/// - string that need to be inserted (in that case, first element of pair is that string and second element is -1)
using Instructions = std::vector<std::pair<int, std::string>>;
static const size_t max_captures = 10;
static Instructions createInstructions(const std::string & s, int num_captures)
{
Instructions instructions;
String now = "";
for (size_t i = 0; i < s.size(); ++i)
{
if (s[i] == '\\' && i + 1 < s.size())
{
if (isNumericASCII(s[i + 1])) /// Substitution
{
if (!now.empty())
{
instructions.emplace_back(-1, now);
now = "";
}
instructions.emplace_back(s[i + 1] - '0', String());
}
else
now += s[i + 1]; /// Escaping
++i;
}
else
now += s[i]; /// Plain character
}
if (!now.empty())
{
instructions.emplace_back(-1, now);
now = "";
}
for (const auto & it : instructions)
if (it.first >= num_captures)
throw Exception(
"Invalid replace instruction in replacement string. Id: " + toString(it.first) + ", but regexp has only "
+ toString(num_captures - 1) + " subpatterns",
ErrorCodes::BAD_ARGUMENTS);
return instructions;
}
static void processString(
const re2_st::StringPiece & input,
ColumnString::Chars & res_data,
ColumnString::Offset & res_offset,
re2_st::RE2 & searcher,
int num_captures,
const Instructions & instructions)
{
re2_st::StringPiece matches[max_captures];
size_t start_pos = 0;
while (start_pos < static_cast<size_t>(input.length()))
{
/// If no more replacements possible for current string
bool can_finish_current_string = false;
if (searcher.Match(input, start_pos, input.length(), re2_st::RE2::Anchor::UNANCHORED, matches, num_captures))
{
const auto & match = matches[0];
size_t bytes_to_copy = (match.data() - input.data()) - start_pos;
/// Copy prefix before matched regexp without modification
res_data.resize(res_data.size() + bytes_to_copy);
memcpySmallAllowReadWriteOverflow15(&res_data[res_offset], input.data() + start_pos, bytes_to_copy);
res_offset += bytes_to_copy;
start_pos += bytes_to_copy + match.length();
/// Do substitution instructions
for (const auto & it : instructions)
{
if (it.first >= 0)
{
res_data.resize(res_data.size() + matches[it.first].length());
memcpy(&res_data[res_offset], matches[it.first].data(), matches[it.first].length());
res_offset += matches[it.first].length();
}
else
{
res_data.resize(res_data.size() + it.second.size());
memcpy(&res_data[res_offset], it.second.data(), it.second.size());
res_offset += it.second.size();
}
}
if (replace_one || match.length() == 0) /// Stop after match of zero length, to avoid infinite loop.
can_finish_current_string = true;
}
else
can_finish_current_string = true;
/// If ready, append suffix after match to end of string.
if (can_finish_current_string)
{
res_data.resize(res_data.size() + input.length() - start_pos);
memcpySmallAllowReadWriteOverflow15(&res_data[res_offset], input.data() + start_pos, input.length() - start_pos);
res_offset += input.length() - start_pos;
start_pos = input.length();
}
}
res_data.resize(res_data.size() + 1);
res_data[res_offset] = 0;
++res_offset;
}
static void vector(
const ColumnString::Chars & data,
const ColumnString::Offsets & offsets,
const std::string & needle,
const std::string & replacement,
ColumnString::Chars & res_data,
ColumnString::Offsets & res_offsets)
{
ColumnString::Offset res_offset = 0;
res_data.reserve(data.size());
size_t size = offsets.size();
res_offsets.resize(size);
re2_st::RE2 searcher(needle);
int num_captures = std::min(searcher.NumberOfCapturingGroups() + 1, static_cast<int>(max_captures));
Instructions instructions = createInstructions(replacement, num_captures);
/// Cannot perform search for whole block. Will process each string separately.
for (size_t i = 0; i < size; ++i)
{
int from = i > 0 ? offsets[i - 1] : 0;
re2_st::StringPiece input(reinterpret_cast<const char *>(data.data() + from), offsets[i] - from - 1);
processString(input, res_data, res_offset, searcher, num_captures, instructions);
res_offsets[i] = res_offset;
}
}
static void vector_fixed(
const ColumnString::Chars & data,
size_t n,
const std::string & needle,
const std::string & replacement,
ColumnString::Chars & res_data,
ColumnString::Offsets & res_offsets)
{
ColumnString::Offset res_offset = 0;
size_t size = data.size() / n;
res_data.reserve(data.size());
res_offsets.resize(size);
re2_st::RE2 searcher(needle);
int num_captures = std::min(searcher.NumberOfCapturingGroups() + 1, static_cast<int>(max_captures));
Instructions instructions = createInstructions(replacement, num_captures);
for (size_t i = 0; i < size; ++i)
{
int from = i * n;
re2_st::StringPiece input(reinterpret_cast<const char *>(data.data() + from), n);
processString(input, res_data, res_offset, searcher, num_captures, instructions);
res_offsets[i] = res_offset;
}
}
};
/** Replace one or all occurencies of substring 'needle' to 'replacement'. 'needle' and 'replacement' are constants.
*/
template <bool replace_one = false>
struct ReplaceStringImpl
{
static void vector(
const ColumnString::Chars & data,
const ColumnString::Offsets & offsets,
const std::string & needle,
const std::string & replacement,
ColumnString::Chars & res_data,
ColumnString::Offsets & res_offsets)
{
const UInt8 * begin = data.data();
const UInt8 * pos = begin;
const UInt8 * end = pos + data.size();
ColumnString::Offset res_offset = 0;
res_data.reserve(data.size());
size_t size = offsets.size();
res_offsets.resize(size);
/// The current index in the array of strings.
size_t i = 0;
Volnitsky searcher(needle.data(), needle.size(), end - pos);
/// We will search for the next occurrence in all rows at once.
while (pos < end)
{
const UInt8 * match = searcher.search(pos, end - pos);
/// Copy the data without changing
res_data.resize(res_data.size() + (match - pos));
memcpy(&res_data[res_offset], pos, match - pos);
/// Determine which index it belongs to.
while (i < offsets.size() && begin + offsets[i] <= match)
{
res_offsets[i] = res_offset + ((begin + offsets[i]) - pos);
++i;
}
res_offset += (match - pos);
/// If you have reached the end, it's time to stop
if (i == offsets.size())
break;
/// Is it true that this string no longer needs to perform transformations.
bool can_finish_current_string = false;
/// We check that the entry does not go through the boundaries of strings.
if (match + needle.size() < begin + offsets[i])
{
res_data.resize(res_data.size() + replacement.size());
memcpy(&res_data[res_offset], replacement.data(), replacement.size());
res_offset += replacement.size();
pos = match + needle.size();
if (replace_one)
can_finish_current_string = true;
}
else
{
pos = match;
can_finish_current_string = true;
}
if (can_finish_current_string)
{
res_data.resize(res_data.size() + (begin + offsets[i] - pos));
memcpy(&res_data[res_offset], pos, (begin + offsets[i] - pos));
res_offset += (begin + offsets[i] - pos);
res_offsets[i] = res_offset;
pos = begin + offsets[i];
++i;
}
}
}
/// Note: this function converts fixed-length strings to variable-length strings
/// and each variable-length string should ends with zero byte.
static void vector_fixed(
const ColumnString::Chars & data,
size_t n,
const std::string & needle,
const std::string & replacement,
ColumnString::Chars & res_data,
ColumnString::Offsets & res_offsets)
{
const UInt8 * begin = data.data();
const UInt8 * pos = begin;
const UInt8 * end = pos + data.size();
ColumnString::Offset res_offset = 0;
size_t count = data.size() / n;
res_data.reserve(data.size());
res_offsets.resize(count);
/// The current index in the string array.
size_t i = 0;
Volnitsky searcher(needle.data(), needle.size(), end - pos);
/// We will search for the next occurrence in all rows at once.
while (pos < end)
{
const UInt8 * match = searcher.search(pos, end - pos);
#define COPY_REST_OF_CURRENT_STRING() \
do \
{ \
const size_t len = begin + n * (i + 1) - pos; \
res_data.resize(res_data.size() + len + 1); \
memcpy(&res_data[res_offset], pos, len); \
res_offset += len; \
res_data[res_offset++] = 0; \
res_offsets[i] = res_offset; \
pos = begin + n * (i + 1); \
++i; \
} while (false)
/// Copy skipped strings without any changes but
/// add zero byte to the end of each string.
while (i < count && begin + n * (i + 1) <= match)
{
COPY_REST_OF_CURRENT_STRING();
}
/// If you have reached the end, it's time to stop
if (i == count)
break;
/// Copy unchanged part of current string.
res_data.resize(res_data.size() + (match - pos));
memcpy(&res_data[res_offset], pos, match - pos);
res_offset += (match - pos);
/// Is it true that this string no longer needs to perform conversions.
bool can_finish_current_string = false;
/// We check that the entry does not pass through the boundaries of strings.
if (match + needle.size() <= begin + n * (i + 1))
{
res_data.resize(res_data.size() + replacement.size());
memcpy(&res_data[res_offset], replacement.data(), replacement.size());
res_offset += replacement.size();
pos = match + needle.size();
if (replace_one || pos == begin + n * (i + 1))
can_finish_current_string = true;
}
else
{
pos = match;
can_finish_current_string = true;
}
if (can_finish_current_string)
{
COPY_REST_OF_CURRENT_STRING();
}
#undef COPY_REST_OF_CURRENT_STRING
}
}
static void constant(const std::string & data, const std::string & needle, const std::string & replacement, std::string & res_data)
{
res_data = "";
int replace_cnt = 0;
for (size_t i = 0; i < data.size(); ++i)
{
bool match = true;
if (i + needle.size() > data.size() || (replace_one && replace_cnt > 0))
match = false;
for (size_t j = 0; match && j < needle.size(); ++j)
if (data[i + j] != needle[j])
match = false;
if (match)
{
++replace_cnt;
res_data += replacement;
i = i + needle.size() - 1;
}
else
res_data += data[i];
}
}
};
template <typename Impl, typename Name>
class FunctionStringReplace : public IFunction
{
public:
static constexpr auto name = Name::name;
static FunctionPtr create(const Context &) { return std::make_shared<FunctionStringReplace>(); }
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 3; }
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1, 2}; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (!isStringOrFixedString(arguments[0]))
throw Exception(
"Illegal type " + arguments[0]->getName() + " of first argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
if (!isStringOrFixedString(arguments[1]))
throw Exception(
"Illegal type " + arguments[1]->getName() + " of second argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
if (!isStringOrFixedString(arguments[2]))
throw Exception(
"Illegal type " + arguments[2]->getName() + " of third argument of function " + getName(),
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
return std::make_shared<DataTypeString>();
}
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
{
const ColumnPtr column_src = block.getByPosition(arguments[0]).column;
const ColumnPtr column_needle = block.getByPosition(arguments[1]).column;
const ColumnPtr column_replacement = block.getByPosition(arguments[2]).column;
if (!column_needle->isColumnConst() || !column_replacement->isColumnConst())
throw Exception("2nd and 3rd arguments of function " + getName() + " must be constants.", ErrorCodes::ILLEGAL_COLUMN);
const IColumn * c1 = block.getByPosition(arguments[1]).column.get();
const IColumn * c2 = block.getByPosition(arguments[2]).column.get();
const ColumnConst * c1_const = typeid_cast<const ColumnConst *>(c1);
const ColumnConst * c2_const = typeid_cast<const ColumnConst *>(c2);
String needle = c1_const->getValue<String>();
String replacement = c2_const->getValue<String>();
if (needle.size() == 0)
throw Exception("Length of the second argument of function replace must be greater than 0.", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
if (const ColumnString * col = checkAndGetColumn<ColumnString>(column_src.get()))
{
auto col_res = ColumnString::create();
Impl::vector(col->getChars(), col->getOffsets(), needle, replacement, col_res->getChars(), col_res->getOffsets());
block.getByPosition(result).column = std::move(col_res);
}
else if (const ColumnFixedString * col_fixed = checkAndGetColumn<ColumnFixedString>(column_src.get()))
{
auto col_res = ColumnString::create();
Impl::vector_fixed(col_fixed->getChars(), col_fixed->getN(), needle, replacement, col_res->getChars(), col_res->getOffsets());
block.getByPosition(result).column = std::move(col_res);
}
else
throw Exception(
"Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function " + getName(),
ErrorCodes::ILLEGAL_COLUMN);
}
};
struct NameMatch
{
static constexpr auto name = "match";
};
struct NameLike
{
static constexpr auto name = "like";
};
struct NameNotLike
{
static constexpr auto name = "notLike";
};
struct NameMultiMatchAny
{
static constexpr auto name = "multiMatchAny";
};
struct NameMultiMatchAnyIndex
{
static constexpr auto name = "multiMatchAnyIndex";
};
struct NameMultiFuzzyMatchAny
{
static constexpr auto name = "multiFuzzyMatchAny";
};
struct NameMultiFuzzyMatchAnyIndex
{
static constexpr auto name = "multiFuzzyMatchAnyIndex";
};
struct NameExtract
{
static constexpr auto name = "extract";
};
struct NameReplaceOne
{
static constexpr auto name = "replaceOne";
};
struct NameReplaceAll
{
static constexpr auto name = "replaceAll";
};
struct NameReplaceRegexpOne
{
static constexpr auto name = "replaceRegexpOne";
};
struct NameReplaceRegexpAll
{
static constexpr auto name = "replaceRegexpAll";
};
using FunctionMatch = FunctionsStringSearch<MatchImpl<false>, NameMatch>;
using FunctionMultiMatchAny = FunctionsMultiStringSearch<
MultiMatchAnyImpl<UInt8, true, false, false>,
NameMultiMatchAny,
std::numeric_limits<UInt32>::max()>;
using FunctionMultiMatchAnyIndex = FunctionsMultiStringSearch<
MultiMatchAnyImpl<UInt64, false, true, false>,
NameMultiMatchAnyIndex,
std::numeric_limits<UInt32>::max()>;
using FunctionMultiFuzzyMatchAny = FunctionsMultiStringFuzzySearch<
MultiMatchAnyImpl<UInt8, true, false, true>,
NameMultiFuzzyMatchAny,
std::numeric_limits<UInt32>::max()>;
using FunctionMultiFuzzyMatchAnyIndex = FunctionsMultiStringFuzzySearch<
MultiMatchAnyImpl<UInt64, false, true, true>,
NameMultiFuzzyMatchAnyIndex,
std::numeric_limits<UInt32>::max()>;
using FunctionLike = FunctionsStringSearch<MatchImpl<true>, NameLike>;
using FunctionNotLike = FunctionsStringSearch<MatchImpl<true, true>, NameNotLike>;
using FunctionExtract = FunctionsStringSearchToString<ExtractImpl, NameExtract>;
using FunctionReplaceOne = FunctionStringReplace<ReplaceStringImpl<true>, NameReplaceOne>;
using FunctionReplaceAll = FunctionStringReplace<ReplaceStringImpl<false>, NameReplaceAll>;
using FunctionReplaceRegexpOne = FunctionStringReplace<ReplaceRegexpImpl<true>, NameReplaceRegexpOne>;
using FunctionReplaceRegexpAll = FunctionStringReplace<ReplaceRegexpImpl<false>, NameReplaceRegexpAll>;
void registerFunctionsStringRegex(FunctionFactory & factory)
{
factory.registerFunction<FunctionMatch>();
factory.registerFunction<FunctionLike>();
factory.registerFunction<FunctionNotLike>();
factory.registerFunction<FunctionExtract>();
factory.registerFunction<FunctionReplaceOne>();
factory.registerFunction<FunctionReplaceAll>();
factory.registerFunction<FunctionReplaceRegexpOne>();
factory.registerFunction<FunctionReplaceRegexpAll>();
factory.registerFunction<FunctionMultiMatchAny>();
factory.registerFunction<FunctionMultiMatchAnyIndex>();
factory.registerFunction<FunctionMultiFuzzyMatchAny>();
factory.registerFunction<FunctionMultiFuzzyMatchAnyIndex>();
factory.registerAlias("replace", NameReplaceAll::name, FunctionFactory::CaseInsensitive);
}
}

View File

@ -0,0 +1,136 @@
#pragma once
#include <Columns/ColumnArray.h>
#include <Columns/ColumnConst.h>
#include <Columns/ColumnString.h>
#include <Columns/ColumnVector.h>
#include <Columns/ColumnsNumber.h>
#include <Core/Field.h>
#include <DataTypes/DataTypeArray.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypesNumber.h>
#include <Functions/FunctionHelpers.h>
#include <Functions/IFunction.h>
#include <IO/WriteHelpers.h>
#include <Interpreters/Context.h>
#include <common/StringRef.h>
#include <optional>
namespace DB
{
namespace ErrorCodes
{
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int ILLEGAL_COLUMN;
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int FUNCTION_NOT_ALLOWED;
}
template <typename Impl, typename Name, size_t LimitArgs>
class FunctionsMultiStringFuzzySearch : public IFunction
{
static_assert(LimitArgs > 0);
public:
static constexpr auto name = Name::name;
static FunctionPtr create(const Context & context)
{
if (Impl::is_using_hyperscan && !context.getSettingsRef().allow_hyperscan)
throw Exception(
"Hyperscan functions are disabled, because setting 'allow_hyperscan' is set to 0", ErrorCodes::FUNCTION_NOT_ALLOWED);
return std::make_shared<FunctionsMultiStringFuzzySearch>();
}
String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 3; }
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1, 2}; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (!isString(arguments[0]))
throw Exception(
"Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
if (!isUnsignedInteger(arguments[1]))
throw Exception(
"Illegal type " + arguments[1]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
const DataTypeArray * array_type = checkAndGetDataType<DataTypeArray>(arguments[2].get());
if (!array_type || !checkAndGetDataType<DataTypeString>(array_type->getNestedType().get()))
throw Exception(
"Illegal type " + arguments[2]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
return std::make_shared<DataTypeNumber<typename Impl::ResultType>>();
}
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
{
using ResultType = typename Impl::ResultType;
const ColumnPtr & column_haystack = block.getByPosition(arguments[0]).column;
const ColumnString * col_haystack_vector = checkAndGetColumn<ColumnString>(&*column_haystack);
const ColumnPtr & num_ptr = block.getByPosition(arguments[1]).column;
const ColumnConst * col_const_num = nullptr;
UInt32 edit_distance = 0;
if ((col_const_num = checkAndGetColumnConst<ColumnUInt8>(num_ptr.get())))
edit_distance = col_const_num->getValue<UInt8>();
else if ((col_const_num = checkAndGetColumnConst<ColumnUInt16>(num_ptr.get())))
edit_distance = col_const_num->getValue<UInt16>();
else if ((col_const_num = checkAndGetColumnConst<ColumnUInt32>(num_ptr.get())))
edit_distance = col_const_num->getValue<UInt32>();
else
throw Exception(
"Illegal column " + block.getByPosition(arguments[1]).column->getName()
+ ". The number is not const or does not fit in UInt32",
ErrorCodes::ILLEGAL_COLUMN);
const ColumnPtr & arr_ptr = block.getByPosition(arguments[2]).column;
const ColumnConst * col_const_arr = checkAndGetColumnConst<ColumnArray>(arr_ptr.get());
if (!col_const_arr)
throw Exception(
"Illegal column " + block.getByPosition(arguments[2]).column->getName() + ". The array is not const",
ErrorCodes::ILLEGAL_COLUMN);
Array src_arr = col_const_arr->getValue<Array>();
if (src_arr.size() > LimitArgs)
throw Exception(
"Number of arguments for function " + getName() + " doesn't match: passed " + std::to_string(src_arr.size())
+ ", should be at most " + std::to_string(LimitArgs),
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
std::vector<StringRef> refs;
refs.reserve(src_arr.size());
for (const auto & el : src_arr)
refs.emplace_back(el.get<String>());
const size_t column_haystack_size = column_haystack->size();
auto col_res = ColumnVector<ResultType>::create();
auto & vec_res = col_res->getData();
vec_res.resize(column_haystack_size);
if (col_haystack_vector)
Impl::vector_constant(col_haystack_vector->getChars(), col_haystack_vector->getOffsets(), refs, vec_res, edit_distance);
else
throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName(), ErrorCodes::ILLEGAL_COLUMN);
block.getByPosition(result).column = std::move(col_res);
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include <Functions/FunctionHelpers.h> #include <Functions/FunctionHelpers.h>
#include <Functions/IFunction.h> #include <Functions/IFunction.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <Interpreters/Context.h>
#include <common/StringRef.h> #include <common/StringRef.h>
namespace DB namespace DB
@ -45,7 +46,7 @@ namespace DB
* multiSearchAllPositionsUTF8(haystack, [pattern_1, pattern_2, ..., pattern_n]) * multiSearchAllPositionsUTF8(haystack, [pattern_1, pattern_2, ..., pattern_n])
* multiSearchAllPositionsCaseInsensitive(haystack, [pattern_1, pattern_2, ..., pattern_n]) * multiSearchAllPositionsCaseInsensitive(haystack, [pattern_1, pattern_2, ..., pattern_n])
* multiSearchAllPositionsCaseInsensitiveUTF8(haystack, [pattern_1, pattern_2, ..., pattern_n]) * multiSearchAllPositionsCaseInsensitiveUTF8(haystack, [pattern_1, pattern_2, ..., pattern_n])
*
* multiSearchFirstPosition(haystack, [pattern_1, pattern_2, ..., pattern_n]) -- returns the first position of the haystack matched by strings or zero if nothing was found * multiSearchFirstPosition(haystack, [pattern_1, pattern_2, ..., pattern_n]) -- returns the first position of the haystack matched by strings or zero if nothing was found
* multiSearchFirstPositionUTF8(haystack, [pattern_1, pattern_2, ..., pattern_n]) * multiSearchFirstPositionUTF8(haystack, [pattern_1, pattern_2, ..., pattern_n])
* multiSearchFirstPositionCaseInsensitive(haystack, [pattern_1, pattern_2, ..., pattern_n]) * multiSearchFirstPositionCaseInsensitive(haystack, [pattern_1, pattern_2, ..., pattern_n])
@ -67,6 +68,7 @@ namespace ErrorCodes
extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ILLEGAL_TYPE_OF_ARGUMENT;
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int FUNCTION_NOT_ALLOWED;
} }
template <typename Impl, typename Name> template <typename Impl, typename Name>
@ -207,15 +209,11 @@ public:
String getName() const override { return name; } String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 2; } size_t getNumberOfArguments() const override { return 2; }
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
if (arguments.size() + 1 >= std::numeric_limits<UInt8>::max())
throw Exception(
"Number of arguments for function " + getName() + " doesn't match: passed " + std::to_string(arguments.size())
+ ", should be at most 255.",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
if (!isString(arguments[0])) if (!isString(arguments[0]))
throw Exception( throw Exception(
"Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); "Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
@ -225,7 +223,6 @@ public:
throw Exception( throw Exception(
"Illegal type " + arguments[1]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); "Illegal type " + arguments[1]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>()); return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>());
} }
@ -247,6 +244,12 @@ public:
Array src_arr = col_const_arr->getValue<Array>(); Array src_arr = col_const_arr->getValue<Array>();
if (src_arr.size() > std::numeric_limits<UInt8>::max())
throw Exception(
"Number of arguments for function " + getName() + " doesn't match: passed " + std::to_string(src_arr.size())
+ ", should be at most 255",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
std::vector<StringRef> refs; std::vector<StringRef> refs;
for (const auto & el : src_arr) for (const auto & el : src_arr)
refs.emplace_back(el.get<String>()); refs.emplace_back(el.get<String>());
@ -285,20 +288,23 @@ class FunctionsMultiStringSearch : public IFunction
public: public:
static constexpr auto name = Name::name; static constexpr auto name = Name::name;
static FunctionPtr create(const Context &) { return std::make_shared<FunctionsMultiStringSearch>(); } static FunctionPtr create(const Context & context)
{
if (Impl::is_using_hyperscan && !context.getSettingsRef().allow_hyperscan)
throw Exception(
"Hyperscan functions are disabled, because setting 'allow_hyperscan' is set to 0", ErrorCodes::FUNCTION_NOT_ALLOWED);
return std::make_shared<FunctionsMultiStringSearch>();
}
String getName() const override { return name; } String getName() const override { return name; }
size_t getNumberOfArguments() const override { return 2; } size_t getNumberOfArguments() const override { return 2; }
bool useDefaultImplementationForConstants() const override { return true; }
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
if (arguments.size() + 1 >= LimitArgs)
throw Exception(
"Number of arguments for function " + getName() + " doesn't match: passed " + std::to_string(arguments.size())
+ ", should be at most " + std::to_string(LimitArgs) + ".",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
if (!isString(arguments[0])) if (!isString(arguments[0]))
throw Exception( throw Exception(
"Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); "Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
@ -330,6 +336,12 @@ public:
Array src_arr = col_const_arr->getValue<Array>(); Array src_arr = col_const_arr->getValue<Array>();
if (src_arr.size() > LimitArgs)
throw Exception(
"Number of arguments for function " + getName() + " doesn't match: passed " + std::to_string(src_arr.size())
+ ", should be at most " + std::to_string(LimitArgs),
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
std::vector<StringRef> refs; std::vector<StringRef> refs;
refs.reserve(src_arr.size()); refs.reserve(src_arr.size());
@ -344,7 +356,6 @@ public:
vec_res.resize(column_haystack_size); vec_res.resize(column_haystack_size);
/// TODO support constant_constant version
if (col_haystack_vector) if (col_haystack_vector)
Impl::vector_constant(col_haystack_vector->getChars(), col_haystack_vector->getOffsets(), refs, vec_res); Impl::vector_constant(col_haystack_vector->getChars(), col_haystack_vector->getOffsets(), refs, vec_res);
else else

View File

@ -318,32 +318,32 @@ struct NgramDistanceImpl
}; };
struct NgramDistanceName struct NameNgramDistance
{ {
static constexpr auto name = "ngramDistance"; static constexpr auto name = "ngramDistance";
}; };
struct NgramDistanceCaseInsensitiveName struct NameNgramDistanceCaseInsensitive
{ {
static constexpr auto name = "ngramDistanceCaseInsensitive"; static constexpr auto name = "ngramDistanceCaseInsensitive";
}; };
struct NgramDistanceUTF8Name struct NameNgramDistanceUTF8
{ {
static constexpr auto name = "ngramDistanceUTF8"; static constexpr auto name = "ngramDistanceUTF8";
}; };
struct NgramDistanceUTF8CaseInsensitiveName struct NameNgramDistanceUTF8CaseInsensitive
{ {
static constexpr auto name = "ngramDistanceCaseInsensitiveUTF8"; static constexpr auto name = "ngramDistanceCaseInsensitiveUTF8";
}; };
using FunctionNgramDistance = FunctionsStringSimilarity<NgramDistanceImpl<4, UInt8, false, false>, NgramDistanceName>; using FunctionNgramDistance = FunctionsStringSimilarity<NgramDistanceImpl<4, UInt8, false, false>, NameNgramDistance>;
using FunctionNgramDistanceCaseInsensitive using FunctionNgramDistanceCaseInsensitive
= FunctionsStringSimilarity<NgramDistanceImpl<4, UInt8, false, true>, NgramDistanceCaseInsensitiveName>; = FunctionsStringSimilarity<NgramDistanceImpl<4, UInt8, false, true>, NameNgramDistanceCaseInsensitive>;
using FunctionNgramDistanceUTF8 = FunctionsStringSimilarity<NgramDistanceImpl<3, UInt32, true, false>, NgramDistanceUTF8Name>; using FunctionNgramDistanceUTF8 = FunctionsStringSimilarity<NgramDistanceImpl<3, UInt32, true, false>, NameNgramDistanceUTF8>;
using FunctionNgramDistanceCaseInsensitiveUTF8 using FunctionNgramDistanceCaseInsensitiveUTF8
= FunctionsStringSimilarity<NgramDistanceImpl<3, UInt32, true, true>, NgramDistanceUTF8CaseInsensitiveName>; = FunctionsStringSimilarity<NgramDistanceImpl<3, UInt32, true, true>, NameNgramDistanceUTF8CaseInsensitive>;
void registerFunctionsStringSimilarity(FunctionFactory & factory) void registerFunctionsStringSimilarity(FunctionFactory & factory)
{ {

View File

@ -9,12 +9,14 @@
namespace DB namespace DB
{ {
/** Calculate similarity metrics: /** Calculate similarity metrics:
* *
* ngramDistance(haystack, needle) --- calculate n-gram distance between haystack and needle. * ngramDistance(haystack, needle) - calculate n-gram distance between haystack and needle.
* Returns float number from 0 to 1 - the closer to zero, the more strings are similar to each other. * Returns float number from 0 to 1 - the closer to zero, the more strings are similar to each other.
* Also support CaseInsensitive and UTF8 formats. * Also support CaseInsensitive and UTF8 formats.
* ngramDistanceCaseInsensitive(haystack, needle)
* ngramDistanceUTF8(haystack, needle)
* ngramDistanceCaseInsensitiveUTF8(haystack, needle)
*/ */
namespace ErrorCodes namespace ErrorCodes
@ -70,11 +72,13 @@ public:
if (needle.size() > Impl::max_string_size) if (needle.size() > Impl::max_string_size)
{ {
throw Exception( throw Exception(
"String size of needle is too big for function " + getName() + ". Should be at most " + std::to_string(Impl::max_string_size), "String size of needle is too big for function " + getName() + ". Should be at most "
ErrorCodes::TOO_LARGE_STRING_SIZE); + std::to_string(Impl::max_string_size),
ErrorCodes::TOO_LARGE_STRING_SIZE);
} }
Impl::constant_constant(col_haystack_const->getValue<String>(), needle, res); Impl::constant_constant(col_haystack_const->getValue<String>(), needle, res);
block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(col_haystack_const->size(), toField(res)); block.getByPosition(result).column
= block.getByPosition(result).type->createColumnConst(col_haystack_const->size(), toField(res));
return; return;
} }
@ -91,11 +95,11 @@ public:
if (needle.size() > Impl::max_string_size) if (needle.size() > Impl::max_string_size)
{ {
throw Exception( throw Exception(
"String size of needle is too big for function " + getName() + ". Should be at most " + std::to_string(Impl::max_string_size), "String size of needle is too big for function " + getName() + ". Should be at most "
ErrorCodes::TOO_LARGE_STRING_SIZE); + std::to_string(Impl::max_string_size),
ErrorCodes::TOO_LARGE_STRING_SIZE);
} }
Impl::vector_constant( Impl::vector_constant(col_haystack_vector->getChars(), col_haystack_vector->getOffsets(), needle, vec_res);
col_haystack_vector->getChars(), col_haystack_vector->getOffsets(), needle, vec_res);
} }
else else
{ {

View File

@ -41,8 +41,7 @@ std::unique_ptr<IArraySink> createArraySink(ColumnArray & col, size_t column_siz
using Creator = ApplyTypeListForClass<ArraySinkCreator, TypeListNumbers>::Type; using Creator = ApplyTypeListForClass<ArraySinkCreator, TypeListNumbers>::Type;
if (auto column_nullable = typeid_cast<ColumnNullable *>(&col.getData())) if (auto column_nullable = typeid_cast<ColumnNullable *>(&col.getData()))
{ {
auto column = ColumnArray::create(column_nullable->getNestedColumnPtr()->assumeMutable(), auto column = ColumnArray::create(column_nullable->getNestedColumnPtr()->assumeMutable(), col.getOffsetsPtr()->assumeMutable());
col.getOffsetsPtr()->assumeMutable());
return Creator::create(*column, &column_nullable->getNullMapData(), column_size); return Creator::create(*column, &column_nullable->getNullMapData(), column_size);
} }
return Creator::create(col, nullptr, column_size); return Creator::create(col, nullptr, column_size);

View File

@ -1,21 +1,23 @@
#pragma once #pragma once
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include <Functions/likePatternToRegexp.h> #include <Functions/likePatternToRegexp.h>
#include <Common/ObjectPool.h> #include <Common/ObjectPool.h>
#include <Common/OptimizedRegularExpression.h> #include <Common/OptimizedRegularExpression.h>
#include <Common/ProfileEvents.h> #include <Common/ProfileEvents.h>
#include <common/StringRef.h> #include <common/StringRef.h>
#include <memory>
#include <string>
#include <vector>
#include <Common/config.h> #include <Common/config.h>
#if USE_HYPERSCAN #if USE_HYPERSCAN
# if __has_include(<hs/hs.h>) # if __has_include(<hs/hs.h>)
# include <hs/hs.h> # include <hs/hs.h>
# else # else
# include <hs.h> # include <hs.h>
# endif # endif
#endif #endif
namespace ProfileEvents namespace ProfileEvents
@ -81,12 +83,15 @@ namespace MultiRegexps
} }
}; };
using CompilerError = std::unique_ptr<hs_compile_error_t, HyperscanDeleter<decltype(&hs_free_compile_error), &hs_free_compile_error>>;
using ScratchPtr = std::unique_ptr<hs_scratch_t, DB::MultiRegexps::HyperscanDeleter<decltype(&hs_free_scratch), &hs_free_scratch>>;
using Regexps = std::unique_ptr<hs_database_t, HyperscanDeleter<decltype(&hs_free_database), &hs_free_database>>; using Regexps = std::unique_ptr<hs_database_t, HyperscanDeleter<decltype(&hs_free_database), &hs_free_database>>;
using Pool = ObjectPoolMap<Regexps, std::vector<String>>; using Pool = ObjectPoolMap<Regexps, std::pair<std::vector<String>, std::optional<UInt32>>>;
template <bool FindAnyIndex> /// If CompileForEditDistance is False, edit_distance must be nullopt
inline Pool::Pointer get(const std::vector<StringRef> & patterns) template <bool FindAnyIndex, bool CompileForEditDistance>
inline Pool::Pointer get(const std::vector<StringRef> & patterns, std::optional<UInt32> edit_distance)
{ {
/// C++11 has thread-safe function-local statics on most modern compilers. /// C++11 has thread-safe function-local statics on most modern compilers.
static Pool known_regexps; /// Different variables for different pattern parameters. static Pool known_regexps; /// Different variables for different pattern parameters.
@ -96,16 +101,37 @@ namespace MultiRegexps
for (const StringRef & ref : patterns) for (const StringRef & ref : patterns)
str_patterns.push_back(ref.toString()); str_patterns.push_back(ref.toString());
return known_regexps.get(str_patterns, [&str_patterns] return known_regexps.get({str_patterns, edit_distance}, [&str_patterns, edit_distance]
{ {
(void)edit_distance;
/// Common pointers
std::vector<const char *> ptrns; std::vector<const char *> ptrns;
std::vector<unsigned int> flags; std::vector<unsigned int> flags;
/// Pointer for external edit distance compilation
std::vector<hs_expr_ext> ext_exprs;
std::vector<const hs_expr_ext *> ext_exprs_ptrs;
ptrns.reserve(str_patterns.size()); ptrns.reserve(str_patterns.size());
flags.reserve(str_patterns.size()); flags.reserve(str_patterns.size());
if constexpr (CompileForEditDistance)
{
ext_exprs.reserve(str_patterns.size());
ext_exprs_ptrs.reserve(str_patterns.size());
}
for (const StringRef ref : str_patterns) for (const StringRef ref : str_patterns)
{ {
ptrns.push_back(ref.data); ptrns.push_back(ref.data);
flags.push_back(HS_FLAG_DOTALL | HS_FLAG_ALLOWEMPTY | HS_FLAG_SINGLEMATCH); flags.push_back(HS_FLAG_DOTALL | HS_FLAG_ALLOWEMPTY | HS_FLAG_SINGLEMATCH);
if constexpr (CompileForEditDistance)
{
ext_exprs.emplace_back();
ext_exprs.back().flags = HS_EXT_FLAG_EDIT_DISTANCE;
ext_exprs.back().edit_distance = edit_distance.value();
ext_exprs_ptrs.push_back(&ext_exprs.back());
}
} }
hs_database_t * db = nullptr; hs_database_t * db = nullptr;
hs_compile_error_t * compile_error; hs_compile_error_t * compile_error;
@ -120,13 +146,32 @@ namespace MultiRegexps
ids[i] = i + 1; ids[i] = i + 1;
} }
hs_error_t err hs_error_t err;
= hs_compile_multi(ptrns.data(), flags.data(), ids.get(), ptrns.size(), HS_MODE_BLOCK, nullptr, &db, &compile_error); if constexpr (!CompileForEditDistance)
err = hs_compile_multi(
ptrns.data(),
flags.data(),
ids.get(),
ptrns.size(),
HS_MODE_BLOCK,
nullptr,
&db,
&compile_error);
else
err = hs_compile_ext_multi(
ptrns.data(),
flags.data(),
ids.get(),
ext_exprs_ptrs.data(),
ptrns.size(),
HS_MODE_BLOCK,
nullptr,
&db,
&compile_error);
if (err != HS_SUCCESS) if (err != HS_SUCCESS)
{ {
std::unique_ptr< CompilerError error(compile_error);
hs_compile_error_t,
HyperscanDeleter<decltype(&hs_free_compile_error), &hs_free_compile_error>> error(compile_error);
if (error->expression < 0) if (error->expression < 0)
throw Exception(String(error->message), ErrorCodes::LOGICAL_ERROR); throw Exception(String(error->message), ErrorCodes::LOGICAL_ERROR);

View File

@ -678,7 +678,7 @@ bool FunctionArrayElement::executeTuple(Block & block, const ColumnNumbers & arg
if (!col_nested) if (!col_nested)
return false; return false;
const Columns & tuple_columns = col_nested->getColumns(); const auto & tuple_columns = col_nested->getColumns();
size_t tuple_size = tuple_columns.size(); size_t tuple_size = tuple_columns.size();
const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>( const DataTypes & tuple_types = typeid_cast<const DataTypeTuple &>(

View File

@ -156,7 +156,7 @@ ColumnPtr FunctionArrayIntersect::castRemoveNullable(const ColumnPtr & column, c
throw Exception{"Cannot cast tuple column to type " throw Exception{"Cannot cast tuple column to type "
+ data_type->getName() + " in function " + getName(), ErrorCodes::LOGICAL_ERROR}; + data_type->getName() + " in function " + getName(), ErrorCodes::LOGICAL_ERROR};
auto columns_number = column_tuple->getColumns().size(); auto columns_number = column_tuple->tupleSize();
Columns columns(columns_number); Columns columns(columns_number);
const auto & types = tuple_type->getElements(); const auto & types = tuple_type->getElements();

View File

@ -545,14 +545,14 @@ private:
Columns col2_contents; Columns col2_contents;
if (const ColumnTuple * tuple1 = typeid_cast<const ColumnTuple *>(arg1.column.get())) if (const ColumnTuple * tuple1 = typeid_cast<const ColumnTuple *>(arg1.column.get()))
col1_contents = tuple1->getColumns(); col1_contents = tuple1->getColumnsCopy();
else if (const ColumnConst * const_tuple = checkAndGetColumnConst<ColumnTuple>(arg1.column.get())) else if (const ColumnConst * const_tuple = checkAndGetColumnConst<ColumnTuple>(arg1.column.get()))
col1_contents = convertConstTupleToConstantElements(*const_tuple); col1_contents = convertConstTupleToConstantElements(*const_tuple);
else else
return false; return false;
if (const ColumnTuple * tuple2 = typeid_cast<const ColumnTuple *>(arg2.column.get())) if (const ColumnTuple * tuple2 = typeid_cast<const ColumnTuple *>(arg2.column.get()))
col2_contents = tuple2->getColumns(); col2_contents = tuple2->getColumnsCopy();
else if (const ColumnConst * const_tuple = checkAndGetColumnConst<ColumnTuple>(arg2.column.get())) else if (const ColumnConst * const_tuple = checkAndGetColumnConst<ColumnTuple>(arg2.column.get()))
col2_contents = convertConstTupleToConstantElements(*const_tuple); col2_contents = convertConstTupleToConstantElements(*const_tuple);
else else

View File

@ -106,7 +106,7 @@ public:
auto set_types = set->getDataTypes(); auto set_types = set->getDataTypes();
if (tuple && (set_types.size() != 1 || !set_types[0]->equals(*type_tuple))) if (tuple && (set_types.size() != 1 || !set_types[0]->equals(*type_tuple)))
{ {
const Columns & tuple_columns = tuple->getColumns(); const auto & tuple_columns = tuple->getColumns();
const DataTypes & tuple_types = type_tuple->getElements(); const DataTypes & tuple_types = type_tuple->getElements();
size_t tuple_size = tuple_columns.size(); size_t tuple_size = tuple_columns.size();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)

View File

@ -1,12 +1,10 @@
#include <Common/config.h>
#include <Functions/registerFunctions.h>
#include <Functions/FunctionFactory.h> #include <Functions/FunctionFactory.h>
#include <Functions/registerFunctions.h>
#include <Common/config.h>
namespace DB namespace DB
{ {
/** These functions are defined in a separate translation units. /** These functions are defined in a separate translation units.
* This is done in order to reduce the consumption of RAM during build, and to speed up the parallel build. * This is done in order to reduce the consumption of RAM during build, and to speed up the parallel build.
*/ */
@ -34,6 +32,7 @@ void registerFunctionsRound(FunctionFactory &);
void registerFunctionsString(FunctionFactory &); void registerFunctionsString(FunctionFactory &);
void registerFunctionsStringArray(FunctionFactory &); void registerFunctionsStringArray(FunctionFactory &);
void registerFunctionsStringSearch(FunctionFactory &); void registerFunctionsStringSearch(FunctionFactory &);
void registerFunctionsStringRegex(FunctionFactory &);
void registerFunctionsStringSimilarity(FunctionFactory &); void registerFunctionsStringSimilarity(FunctionFactory &);
void registerFunctionsURL(FunctionFactory &); void registerFunctionsURL(FunctionFactory &);
void registerFunctionsVisitParam(FunctionFactory &); void registerFunctionsVisitParam(FunctionFactory &);
@ -75,6 +74,7 @@ void registerFunctions()
registerFunctionsString(factory); registerFunctionsString(factory);
registerFunctionsStringArray(factory); registerFunctionsStringArray(factory);
registerFunctionsStringSearch(factory); registerFunctionsStringSearch(factory);
registerFunctionsStringRegex(factory);
registerFunctionsStringSimilarity(factory); registerFunctionsStringSimilarity(factory);
registerFunctionsURL(factory); registerFunctionsURL(factory);
registerFunctionsVisitParam(factory); registerFunctionsVisitParam(factory);

View File

@ -79,3 +79,6 @@ target_link_libraries (parse_date_time_best_effort PRIVATE clickhouse_common_io)
add_executable (zlib_ng_bug zlib_ng_bug.cpp) add_executable (zlib_ng_bug zlib_ng_bug.cpp)
target_link_libraries (zlib_ng_bug PRIVATE ${Poco_Foundation_LIBRARY}) target_link_libraries (zlib_ng_bug PRIVATE ${Poco_Foundation_LIBRARY})
if(NOT USE_INTERNAL_POCO_LIBRARY)
target_include_directories(zlib_ng_bug SYSTEM BEFORE PRIVATE ${Poco_INCLUDE_DIRS})
endif()

View File

@ -32,23 +32,54 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
static NameSet requiredRightKeys(const Names & key_names, const NamesAndTypesList & columns_added_by_join)
{
NameSet required;
static std::unordered_map<String, DataTypePtr> requiredRightKeys(const Names & key_names, const NamesAndTypesList & columns_added_by_join)
{
NameSet right_keys; NameSet right_keys;
for (const auto & name : key_names) for (const auto & name : key_names)
right_keys.insert(name); right_keys.insert(name);
std::unordered_map<String, DataTypePtr> required;
for (const auto & column : columns_added_by_join) for (const auto & column : columns_added_by_join)
{
if (right_keys.count(column.name)) if (right_keys.count(column.name))
required.insert(column.name); required.insert({column.name, column.type});
}
return required; return required;
} }
static void convertColumnToNullable(ColumnWithTypeAndName & column)
{
if (column.type->isNullable())
return;
column.type = makeNullable(column.type);
if (column.column)
column.column = makeNullable(column.column);
}
/// Converts column to nullable if needed. No backward convertion.
static ColumnWithTypeAndName correctNullability(ColumnWithTypeAndName && column, bool nullable)
{
if (nullable)
convertColumnToNullable(column);
return std::move(column);
}
static ColumnWithTypeAndName correctNullability(ColumnWithTypeAndName && column, bool nullable, const ColumnUInt8 & negative_null_map)
{
if (nullable)
{
convertColumnToNullable(column);
if (negative_null_map.size())
{
MutableColumnPtr mutable_column = (*std::move(column.column)).mutate();
static_cast<ColumnNullable &>(*mutable_column).applyNegatedNullMap(negative_null_map);
column.column = std::move(mutable_column);
}
}
return std::move(column);
}
Join::Join(const Names & key_names_right_, bool use_nulls_, const SizeLimits & limits, Join::Join(const Names & key_names_right_, bool use_nulls_, const SizeLimits & limits,
ASTTableJoin::Kind kind_, ASTTableJoin::Strictness strictness_, bool any_take_last_row_) ASTTableJoin::Kind kind_, ASTTableJoin::Strictness strictness_, bool any_take_last_row_)
@ -119,6 +150,25 @@ Join::Type Join::chooseMethod(const ColumnRawPtrs & key_columns, Sizes & key_siz
return Type::hashed; return Type::hashed;
} }
static const IColumn * extractAsofColumn(const ColumnRawPtrs & key_columns)
{
return key_columns.back();
}
template<typename KeyGetter, ASTTableJoin::Strictness STRICTNESS>
static KeyGetter createKeyGetter(const ColumnRawPtrs & key_columns, const Sizes & key_sizes)
{
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
{
auto key_column_copy = key_columns;
auto key_size_copy = key_sizes;
key_column_copy.pop_back();
key_size_copy.pop_back();
return KeyGetter(key_column_copy, key_size_copy, nullptr);
}
else
return KeyGetter(key_columns, key_sizes, nullptr);
}
template <Join::Type type, typename Value, typename Mapped> template <Join::Type type, typename Value, typename Mapped>
struct KeyGetterForTypeImpl; struct KeyGetterForTypeImpl;
@ -215,18 +265,10 @@ size_t Join::getTotalByteCount() const
return res; return res;
} }
static void convertColumnToNullable(ColumnWithTypeAndName & column)
{
column.type = makeNullable(column.type);
if (column.column)
column.column = makeNullable(column.column);
}
void Join::setSampleBlock(const Block & block) void Join::setSampleBlock(const Block & block)
{ {
std::unique_lock lock(rwlock); std::unique_lock lock(rwlock);
LOG_DEBUG(log, "setSampleBlock: " << block.dumpStructure());
if (!empty()) if (!empty())
return; return;
@ -251,8 +293,35 @@ void Join::setSampleBlock(const Block & block)
key_columns[i] = &static_cast<const ColumnNullable &>(*key_columns[i]).getNestedColumn(); key_columns[i] = &static_cast<const ColumnNullable &>(*key_columns[i]).getNestedColumn();
} }
/// Choose data structure to use for JOIN. if (strictness == ASTTableJoin::Strictness::Asof)
init(chooseMethod(key_columns, key_sizes)); {
if (kind != ASTTableJoin::Kind::Left and kind != ASTTableJoin::Kind::Inner)
throw Exception("ASOF only supports LEFT and INNER as base joins", ErrorCodes::NOT_IMPLEMENTED);
if (key_columns.back()->sizeOfValueIfFixed() != sizeof(ASOFTimeType))
{
std::string msg = "ASOF join column needs to have size ";
msg += std::to_string(sizeof(ASOFTimeType));
throw Exception(msg, ErrorCodes::BAD_TYPE_OF_FIELD);
}
key_columns.pop_back();
if (key_columns.empty())
throw Exception("ASOF join cannot be done without a joining column", ErrorCodes::LOGICAL_ERROR);
/// this is going to set up the appropriate hash table for the direct lookup part of the join
/// However, this does not depend on the size of the asof join key (as that goes into the BST)
/// Therefore, add it back in such that it can be extracted appropriately from the full stored
/// key_columns and key_sizes
init(chooseMethod(key_columns, key_sizes));
key_sizes.push_back(sizeof(ASOFTimeType));
}
else
{
/// Choose data structure to use for JOIN.
init(chooseMethod(key_columns, key_sizes));
}
sample_block_with_columns_to_add = materializeBlock(block); sample_block_with_columns_to_add = materializeBlock(block);
@ -288,6 +357,33 @@ void Join::setSampleBlock(const Block & block)
convertColumnToNullable(sample_block_with_columns_to_add.getByPosition(i)); convertColumnToNullable(sample_block_with_columns_to_add.getByPosition(i));
} }
void Join::TSRowRef::insert(Join::ASOFTimeType t, const Block * block, size_t row_num)
{
ts.insert(std::pair(t, RowRef(block, row_num)));
}
std::string Join::TSRowRef::dumpStructure() const
{
std::stringstream ss;
for (auto const& x : ts)
{
ss << "(t=" << x.first << " row_num=" << x.second.row_num << " ptr=" << x.second.block << "),";
}
return ss.str();
}
size_t Join::TSRowRef::size() const
{
return ts.size();
}
std::optional<std::pair<Join::ASOFTimeType, Join::RowRef>> Join::TSRowRef::findAsof(Join::ASOFTimeType t) const
{
auto it = ts.upper_bound(t);
if (it == ts.cbegin())
return {};
return *(--it);
}
namespace namespace
{ {
@ -336,20 +432,48 @@ namespace
} }
}; };
template <typename Map, typename KeyGetter>
struct Inserter<ASTTableJoin::Strictness::Asof, Map, KeyGetter>
{
template<typename AsofGetter>
static ALWAYS_INLINE void insert(Map & map, KeyGetter & key_getter, AsofGetter & asof_getter, Block * stored_block, size_t i, Arena & pool)
{
auto emplace_result = key_getter.emplaceKey(map, i, pool);
typename Map::mapped_type * time_series_map = &emplace_result.getMapped();
if (emplace_result.isInserted())
{
time_series_map = new (time_series_map) typename Map::mapped_type();
}
auto k = asof_getter.getKey(i, pool);
time_series_map->insert(k, stored_block, i);
// std::cout << "inserted key into time series map=" << k << " result=" << time_series_map->dumpStructure() << std::endl;
}
};
template <ASTTableJoin::Strictness STRICTNESS, typename KeyGetter, typename Map, bool has_null_map> template <ASTTableJoin::Strictness STRICTNESS, typename KeyGetter, typename Map, bool has_null_map>
void NO_INLINE insertFromBlockImplTypeCase( void NO_INLINE insertFromBlockImplTypeCase(
Map & map, size_t rows, const ColumnRawPtrs & key_columns, Map & map, size_t rows, const ColumnRawPtrs & key_columns,
const Sizes & key_sizes, Block * stored_block, ConstNullMapPtr null_map, Arena & pool) const Sizes & key_sizes, Block * stored_block, ConstNullMapPtr null_map, Arena & pool)
{ {
KeyGetter key_getter(key_columns, key_sizes, nullptr); const IColumn * asof_column [[maybe_unused]] = nullptr;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
asof_column = extractAsofColumn(key_columns);
auto key_getter = createKeyGetter<KeyGetter, STRICTNESS>(key_columns, key_sizes);
for (size_t i = 0; i < rows; ++i) for (size_t i = 0; i < rows; ++i)
{ {
if (has_null_map && (*null_map)[i]) if (has_null_map && (*null_map)[i])
continue; continue;
Inserter<STRICTNESS, Map, KeyGetter>::insert(map, key_getter, stored_block, i, pool); if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
{
auto asof_getter = Join::AsofGetterType(asof_column);
Inserter<STRICTNESS, Map, KeyGetter>::insert(map, key_getter, asof_getter, stored_block, i, pool);
} else
Inserter<STRICTNESS, Map, KeyGetter>::insert(map, key_getter, stored_block, i, pool);
} }
} }
@ -387,10 +511,10 @@ namespace
} }
} }
bool Join::insertFromBlock(const Block & block) bool Join::insertFromBlock(const Block & block)
{ {
std::unique_lock lock(rwlock); std::unique_lock lock(rwlock);
LOG_DEBUG(log, "joinBlock: " << block.dumpStructure());
if (empty()) if (empty())
throw Exception("Logical error: Join was not initialized", ErrorCodes::LOGICAL_ERROR); throw Exception("Logical error: Join was not initialized", ErrorCodes::LOGICAL_ERROR);
@ -515,6 +639,7 @@ public:
columns[j]->insertFrom(*block.getByPosition(right_indexes[j]).column, row_num); columns[j]->insertFrom(*block.getByPosition(right_indexes[j]).column, row_num);
} }
void appendDefaultRow() void appendDefaultRow()
{ {
for (size_t j = 0; j < right_indexes.size(); ++j) for (size_t j = 0; j < right_indexes.size(); ++j)
@ -553,6 +678,20 @@ void addFoundRow(const typename Map::mapped_type & mapped, AddedColumns & added,
} }
}; };
template <typename Map>
bool addFoundRowAsof(const typename Map::mapped_type & mapped, AddedColumns & added, IColumn::Offset & current_offset [[maybe_unused]], Join::ASOFTimeType asof_key)
{
if (auto v = mapped.findAsof(asof_key))
{
std::pair<Join::ASOFTimeType, Join::RowRef> res = *v;
// std::cout << "Adder::addFound" << " to_add" << num_columns_to_add << " i=" << i << " asof_key=" << asof_key << " found=" << res.first << std::endl;
added.appendFromBlock(*res.second.block, res.second.row_num);
return true;
}
// std::cout << "Adder::addFound" << " not found in map" << num_columns_to_add << " i=" << i << " asof_key=" << asof_key << std::endl;
return false;
}
template <bool _add_missing> template <bool _add_missing>
void addNotFoundRow(AddedColumns & added [[maybe_unused]], IColumn::Offset & current_offset [[maybe_unused]]) void addNotFoundRow(AddedColumns & added [[maybe_unused]], IColumn::Offset & current_offset [[maybe_unused]])
{ {
@ -563,20 +702,28 @@ void addNotFoundRow(AddedColumns & added [[maybe_unused]], IColumn::Offset & cur
} }
} }
/// Joins right table columns which indexes are present in right_indexes using specified map. /// Joins right table columns which indexes are present in right_indexes using specified map.
/// Makes filter (1 if row presented in right table) and returns offsets to replicate (for ALL JOINS). /// Makes filter (1 if row presented in right table) and returns offsets to replicate (for ALL JOINS).
template <bool _add_missing, ASTTableJoin::Strictness STRICTNESS, typename KeyGetter, typename Map, bool _has_null_map> template <bool _add_missing, ASTTableJoin::Strictness STRICTNESS, typename KeyGetter, typename Map, bool _has_null_map>
std::unique_ptr<IColumn::Offsets> NO_INLINE joinRightIndexedColumns( std::unique_ptr<IColumn::Offsets> NO_INLINE joinRightIndexedColumns(
const Map & map, size_t rows, KeyGetter & key_getter, const Map & map, size_t rows, const ColumnRawPtrs & key_columns, const Sizes & key_sizes,
AddedColumns & added_columns, ConstNullMapPtr null_map, IColumn::Filter & filter) AddedColumns & added_columns, ConstNullMapPtr null_map, IColumn::Filter & filter)
{ {
std::unique_ptr<IColumn::Offsets> offsets_to_replicate; std::unique_ptr<IColumn::Offsets> offsets_to_replicate;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::All) if constexpr (STRICTNESS == ASTTableJoin::Strictness::All)
offsets_to_replicate = std::make_unique<IColumn::Offsets>(rows); offsets_to_replicate = std::make_unique<IColumn::Offsets>(rows);
IColumn::Offset current_offset = 0;
Arena pool; Arena pool;
const IColumn * asof_column [[maybe_unused]] = nullptr;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
asof_column = extractAsofColumn(key_columns);
auto key_getter = createKeyGetter<KeyGetter, STRICTNESS>(key_columns, key_sizes);
IColumn::Offset current_offset = 0;
for (size_t i = 0; i < rows; ++i) for (size_t i = 0; i < rows; ++i)
{ {
if (_has_null_map && (*null_map)[i]) if (_has_null_map && (*null_map)[i])
@ -589,10 +736,28 @@ std::unique_ptr<IColumn::Offsets> NO_INLINE joinRightIndexedColumns(
if (find_result.isFound()) if (find_result.isFound())
{ {
filter[i] = 1;
auto & mapped = find_result.getMapped(); auto & mapped = find_result.getMapped();
mapped.setUsed();
addFoundRow<STRICTNESS, Map>(mapped, added_columns, current_offset); if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
{
Join::AsofGetterType asof_getter(asof_column);
auto asof_key = asof_getter.getKey(i, pool);
bool actually_found = addFoundRowAsof<Map>(mapped, added_columns, current_offset, asof_key);
if (actually_found)
{
filter[i] = 1;
mapped.setUsed();
}
else
addNotFoundRow<_add_missing>(added_columns, current_offset);
}
else
{
filter[i] = 1;
mapped.setUsed();
addFoundRow<STRICTNESS, Map>(mapped, added_columns, current_offset);
}
} }
else else
addNotFoundRow<_add_missing>(added_columns, current_offset); addNotFoundRow<_add_missing>(added_columns, current_offset);
@ -613,14 +778,13 @@ IColumn::Filter joinRightColumns(
constexpr bool left_or_full = static_in_v<KIND, ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Full>; constexpr bool left_or_full = static_in_v<KIND, ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Full>;
IColumn::Filter filter(rows, 0); IColumn::Filter filter(rows, 0);
KeyGetter key_getter(key_columns, key_sizes, nullptr);
if (null_map) if (null_map)
offsets_to_replicate = joinRightIndexedColumns<left_or_full, STRICTNESS, KeyGetter, Map, true>( offsets_to_replicate = joinRightIndexedColumns<left_or_full, STRICTNESS, KeyGetter, Map, true>(
map, rows, key_getter, added_columns, null_map, filter); map, rows, key_columns, key_sizes, added_columns, null_map, filter);
else else
offsets_to_replicate = joinRightIndexedColumns<left_or_full, STRICTNESS, KeyGetter, Map, false>( offsets_to_replicate = joinRightIndexedColumns<left_or_full, STRICTNESS, KeyGetter, Map, false>(
map, rows, key_getter, added_columns, null_map, filter); map, rows, key_columns, key_sizes, added_columns, null_map, filter);
return filter; return filter;
} }
@ -712,7 +876,7 @@ void Join::joinBlockImpl(
std::unique_ptr<IColumn::Offsets> offsets_to_replicate; std::unique_ptr<IColumn::Offsets> offsets_to_replicate;
IColumn::Filter filter = switchJoinRightColumns<KIND, STRICTNESS>( IColumn::Filter row_filter = switchJoinRightColumns<KIND, STRICTNESS>(
type, maps_, block.rows(), key_columns, key_sizes, added, null_map, offsets_to_replicate); type, maps_, block.rows(), key_columns, key_sizes, added, null_map, offsets_to_replicate);
for (size_t i = 0; i < added.size(); ++i) for (size_t i = 0; i < added.size(); ++i)
@ -720,10 +884,16 @@ void Join::joinBlockImpl(
/// Filter & insert missing rows /// Filter & insert missing rows
NameSet needed_key_names_right = requiredRightKeys(key_names_right, columns_added_by_join); auto right_keys = requiredRightKeys(key_names_right, columns_added_by_join);
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any) if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any || STRICTNESS == ASTTableJoin::Strictness::Asof)
{ {
/// Some trash to represent IColumn::Filter as ColumnUInt8 needed for ColumnNullable::applyNullMap()
auto null_map_filter_ptr = ColumnUInt8::create();
ColumnUInt8 & null_map_filter = static_cast<ColumnUInt8 &>(*null_map_filter_ptr);
null_map_filter.getData().swap(row_filter);
const IColumn::Filter & filter = null_map_filter.getData();
constexpr bool inner_or_right = static_in_v<KIND, ASTTableJoin::Kind::Inner, ASTTableJoin::Kind::Right>; constexpr bool inner_or_right = static_in_v<KIND, ASTTableJoin::Kind::Inner, ASTTableJoin::Kind::Right>;
if constexpr (inner_or_right) if constexpr (inner_or_right)
{ {
@ -737,10 +907,12 @@ void Join::joinBlockImpl(
auto & right_name = key_names_right[i]; auto & right_name = key_names_right[i];
auto & left_name = key_names_left[i]; auto & left_name = key_names_left[i];
if (needed_key_names_right.count(right_name) && !block.has(right_name)) auto it = right_keys.find(right_name);
if (it != right_keys.end() && !block.has(right_name))
{ {
const auto & col = block.getByName(left_name); const auto & col = block.getByName(left_name);
block.insert({col.column, col.type, right_name}); bool is_nullable = it->second->isNullable();
block.insert(correctNullability({col.column, col.type, right_name}, is_nullable));
} }
} }
} }
@ -752,7 +924,8 @@ void Join::joinBlockImpl(
auto & right_name = key_names_right[i]; auto & right_name = key_names_right[i];
auto & left_name = key_names_left[i]; auto & left_name = key_names_left[i];
if (needed_key_names_right.count(right_name) && !block.has(right_name)) auto it = right_keys.find(right_name);
if (it != right_keys.end() && !block.has(right_name))
{ {
const auto & col = block.getByName(left_name); const auto & col = block.getByName(left_name);
ColumnPtr column = col.column->convertToFullColumnIfConst(); ColumnPtr column = col.column->convertToFullColumnIfConst();
@ -766,13 +939,15 @@ void Join::joinBlockImpl(
mut_column->insertDefault(); mut_column->insertDefault();
} }
block.insert({std::move(mut_column), col.type, right_name}); bool is_nullable = use_nulls || it->second->isNullable();
block.insert(correctNullability({std::move(mut_column), col.type, right_name}, is_nullable, null_map_filter));
} }
} }
} }
} }
else else
{ {
constexpr bool left_or_full = static_in_v<KIND, ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Full>;
if (!offsets_to_replicate) if (!offsets_to_replicate)
throw Exception("No data to filter columns", ErrorCodes::LOGICAL_ERROR); throw Exception("No data to filter columns", ErrorCodes::LOGICAL_ERROR);
@ -782,7 +957,8 @@ void Join::joinBlockImpl(
auto & right_name = key_names_right[i]; auto & right_name = key_names_right[i];
auto & left_name = key_names_left[i]; auto & left_name = key_names_left[i];
if (needed_key_names_right.count(right_name) && !block.has(right_name)) auto it = right_keys.find(right_name);
if (it != right_keys.end() && !block.has(right_name))
{ {
const auto & col = block.getByName(left_name); const auto & col = block.getByName(left_name);
ColumnPtr column = col.column->convertToFullColumnIfConst(); ColumnPtr column = col.column->convertToFullColumnIfConst();
@ -793,7 +969,7 @@ void Join::joinBlockImpl(
{ {
if (size_t to_insert = (*offsets_to_replicate)[row] - last_offset) if (size_t to_insert = (*offsets_to_replicate)[row] - last_offset)
{ {
if (!filter[row]) if (!row_filter[row])
mut_column->insertDefault(); mut_column->insertDefault();
else else
for (size_t dup = 0; dup < to_insert; ++dup) for (size_t dup = 0; dup < to_insert; ++dup)
@ -803,7 +979,9 @@ void Join::joinBlockImpl(
last_offset = (*offsets_to_replicate)[row]; last_offset = (*offsets_to_replicate)[row];
} }
block.insert({std::move(mut_column), col.type, right_name}); /// TODO: null_map_filter
bool is_nullable = (use_nulls && left_or_full) || it->second->isNullable();
block.insert(correctNullability({std::move(mut_column), col.type, right_name}, is_nullable));
} }
} }
@ -943,9 +1121,8 @@ void Join::joinGet(Block & block, const String & column_name) const
void Join::joinBlock(Block & block, const Names & key_names_left, const NamesAndTypesList & columns_added_by_join) const void Join::joinBlock(Block & block, const Names & key_names_left, const NamesAndTypesList & columns_added_by_join) const
{ {
// std::cerr << "joinBlock: " << block.dumpStructure() << "\n";
std::shared_lock lock(rwlock); std::shared_lock lock(rwlock);
LOG_DEBUG(log, "joinBlock: " << block.dumpStructure());
checkTypesOfKeys(block, key_names_left, sample_block_with_keys); checkTypesOfKeys(block, key_names_left, sample_block_with_keys);
@ -997,11 +1174,8 @@ struct AdderNonJoined;
template <typename Mapped> template <typename Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::Any, Mapped> struct AdderNonJoined<ASTTableJoin::Strictness::Any, Mapped>
{ {
static void add(const Mapped & mapped, size_t & rows_added, MutableColumns & columns_left, MutableColumns & columns_right) static void add(const Mapped & mapped, size_t & rows_added, MutableColumns & columns_right)
{ {
for (size_t j = 0; j < columns_left.size(); ++j)
columns_left[j]->insertDefault();
for (size_t j = 0; j < columns_right.size(); ++j) for (size_t j = 0; j < columns_right.size(); ++j)
columns_right[j]->insertFrom(*mapped.block->getByPosition(j).column.get(), mapped.row_num); columns_right[j]->insertFrom(*mapped.block->getByPosition(j).column.get(), mapped.row_num);
@ -1012,13 +1186,10 @@ struct AdderNonJoined<ASTTableJoin::Strictness::Any, Mapped>
template <typename Mapped> template <typename Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::All, Mapped> struct AdderNonJoined<ASTTableJoin::Strictness::All, Mapped>
{ {
static void add(const Mapped & mapped, size_t & rows_added, MutableColumns & columns_left, MutableColumns & columns_right) static void add(const Mapped & mapped, size_t & rows_added, MutableColumns & columns_right)
{ {
for (auto current = &static_cast<const typename Mapped::Base_t &>(mapped); current != nullptr; current = current->next) for (auto current = &static_cast<const typename Mapped::Base_t &>(mapped); current != nullptr; current = current->next)
{ {
for (size_t j = 0; j < columns_left.size(); ++j)
columns_left[j]->insertDefault();
for (size_t j = 0; j < columns_right.size(); ++j) for (size_t j = 0; j < columns_right.size(); ++j)
columns_right[j]->insertFrom(*current->block->getByPosition(j).column.get(), current->row_num); columns_right[j]->insertFrom(*current->block->getByPosition(j).column.get(), current->row_num);
@ -1027,6 +1198,14 @@ struct AdderNonJoined<ASTTableJoin::Strictness::All, Mapped>
} }
}; };
template <typename Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::Asof, Mapped>
{
static void add(const Mapped & /*mapped*/, size_t & /*rows_added*/, MutableColumns & /*columns_right*/)
{
// If we have a leftover match in the right hand side, not required to join because we are only support asof left/inner
}
};
/// Stream from not joined earlier rows of the right table. /// Stream from not joined earlier rows of the right table.
class NonJoinedBlockInputStream : public IBlockInputStream class NonJoinedBlockInputStream : public IBlockInputStream
@ -1040,53 +1219,51 @@ public:
* result_sample_block - keys, "left" columns, and "right" columns. * result_sample_block - keys, "left" columns, and "right" columns.
*/ */
std::unordered_map<String, String> key_renames;
makeResultSampleBlock(left_sample_block, key_names_left, columns_added_by_join, key_renames);
const Block & right_sample_block = parent.sample_block_with_columns_to_add;
size_t num_keys = key_names_left.size();
size_t num_columns_left = left_sample_block.columns() - num_keys;
size_t num_columns_right = right_sample_block.columns();
column_indices_left.reserve(num_columns_left);
column_indices_keys_and_right.reserve(num_keys + num_columns_right);
std::vector<bool> is_left_key(left_sample_block.columns(), false); std::vector<bool> is_left_key(left_sample_block.columns(), false);
std::vector<size_t> key_positions_left;
key_positions_left.reserve(key_names_left.size());
for (const std::string & key : key_names_left) for (const std::string & key : key_names_left)
{ {
size_t key_pos = left_sample_block.getPositionByName(key); size_t key_pos = left_sample_block.getPositionByName(key);
key_positions_left.push_back(key_pos);
is_left_key[key_pos] = true; is_left_key[key_pos] = true;
}
const Block & right_sample_block = parent.sample_block_with_columns_to_add;
std::unordered_map<size_t, size_t> left_to_right_key_map;
makeResultSampleBlock(left_sample_block, right_sample_block, columns_added_by_join,
key_positions_left, is_left_key, left_to_right_key_map);
column_indices_left.reserve(left_sample_block.columns() - key_names_left.size());
column_indices_keys_and_right.reserve(key_names_left.size() + right_sample_block.columns());
/// Use right key columns if present. @note left & right key columns could have different nullability.
for (size_t key_pos : key_positions_left)
{
/// Here we establish the mapping between key columns of the left- and right-side tables. /// Here we establish the mapping between key columns of the left- and right-side tables.
/// key_pos index is inserted in the position corresponding to key column in parent.blocks /// key_pos index is inserted in the position corresponding to key column in parent.blocks
/// (saved blocks of the right-side table) and points to the same key column /// (saved blocks of the right-side table) and points to the same key column
/// in the left_sample_block and thus in the result_sample_block. /// in the left_sample_block and thus in the result_sample_block.
column_indices_keys_and_right.push_back(key_pos);
auto it = key_renames.find(key); auto it = left_to_right_key_map.find(key_pos);
if (it != key_renames.end()) if (it != left_to_right_key_map.end())
key_renames_indices[key_pos] = result_sample_block.getPositionByName(it->second);
}
size_t num_src_columns = left_sample_block.columns() + right_sample_block.columns();
for (size_t i = 0; i < result_sample_block.columns(); ++i)
{
if (i < left_sample_block.columns())
{ {
if (!is_left_key[i]) column_indices_keys_and_right.push_back(it->second);
{ column_indices_left.push_back(key_pos);
column_indices_left.emplace_back(i);
/// If use_nulls, convert left columns to Nullable.
if (parent.use_nulls)
convertColumnToNullable(result_sample_block.getByPosition(i));
}
} }
else if (i < num_src_columns) else
column_indices_keys_and_right.emplace_back(i); column_indices_keys_and_right.push_back(key_pos);
} }
for (size_t i = 0; i < left_sample_block.columns(); ++i)
if (!is_left_key[i])
column_indices_left.emplace_back(i);
size_t num_additional_keys = left_to_right_key_map.size();
for (size_t i = left_sample_block.columns(); i < result_sample_block.columns() - num_additional_keys; ++i)
column_indices_keys_and_right.emplace_back(i);
} }
String getName() const override { return "NonJoined"; } String getName() const override { return "NonJoined"; }
@ -1118,18 +1295,25 @@ private:
/// Indices of key columns in result_sample_block or columns that come from the right-side table. /// Indices of key columns in result_sample_block or columns that come from the right-side table.
/// Order is significant: it is the same as the order of columns in the blocks of the right-side table that are saved in parent.blocks. /// Order is significant: it is the same as the order of columns in the blocks of the right-side table that are saved in parent.blocks.
ColumnNumbers column_indices_keys_and_right; ColumnNumbers column_indices_keys_and_right;
std::unordered_map<size_t, size_t> key_renames_indices;
std::unique_ptr<void, std::function<void(void *)>> position; /// type erasure std::unique_ptr<void, std::function<void(void *)>> position; /// type erasure
void makeResultSampleBlock(const Block & left_sample_block, const Names & key_names_left, void makeResultSampleBlock(const Block & left_sample_block, const Block & right_sample_block,
const NamesAndTypesList & columns_added_by_join, std::unordered_map<String, String> & key_renames) const NamesAndTypesList & columns_added_by_join,
const std::vector<size_t> & key_positions_left, const std::vector<bool> & is_left_key,
std::unordered_map<size_t, size_t> & left_to_right_key_map)
{ {
const Block & right_sample_block = parent.sample_block_with_columns_to_add;
result_sample_block = materializeBlock(left_sample_block); result_sample_block = materializeBlock(left_sample_block);
/// Convert left columns to Nullable if allowed
if (parent.use_nulls)
{
for (size_t i = 0; i < result_sample_block.columns(); ++i)
if (!is_left_key[i])
convertColumnToNullable(result_sample_block.getByPosition(i));
}
/// Add columns from the right-side table to the block. /// Add columns from the right-side table to the block.
for (size_t i = 0; i < right_sample_block.columns(); ++i) for (size_t i = 0; i < right_sample_block.columns(); ++i)
{ {
@ -1139,20 +1323,23 @@ private:
} }
const auto & key_names_right = parent.key_names_right; const auto & key_names_right = parent.key_names_right;
NameSet needed_key_names_right = requiredRightKeys(key_names_right, columns_added_by_join); auto right_keys = requiredRightKeys(key_names_right, columns_added_by_join);
/// Add join key columns from right block if they has different name. /// Add join key columns from right block if they has different name.
for (size_t i = 0; i < key_names_right.size(); ++i) for (size_t i = 0; i < key_names_right.size(); ++i)
{ {
auto & right_name = key_names_right[i]; auto & right_name = key_names_right[i];
auto & left_name = key_names_left[i]; size_t left_key_pos = key_positions_left[i];
if (needed_key_names_right.count(right_name) && !result_sample_block.has(right_name)) auto it = right_keys.find(right_name);
if (it != right_keys.end() && !result_sample_block.has(right_name))
{ {
const auto & col = result_sample_block.getByName(left_name); const auto & col = result_sample_block.getByPosition(left_key_pos);
result_sample_block.insert({col.column, col.type, right_name}); bool is_nullable = (parent.use_nulls && isFull(parent.kind)) || it->second->isNullable();
result_sample_block.insert(correctNullability({col.column, col.type, right_name}, is_nullable));
key_renames[left_name] = right_name; size_t right_key_pos = result_sample_block.getPositionByName(right_name);
left_to_right_key_map[left_key_pos] = right_key_pos;
} }
} }
} }
@ -1169,7 +1356,7 @@ private:
{ {
#define M(TYPE) \ #define M(TYPE) \
case Join::Type::TYPE: \ case Join::Type::TYPE: \
rows_added = fillColumns<STRICTNESS>(*maps.TYPE, columns_left, columns_keys_and_right); \ rows_added = fillColumns<STRICTNESS>(*maps.TYPE, columns_keys_and_right); \
break; break;
APPLY_FOR_JOIN_VARIANTS(M) APPLY_FOR_JOIN_VARIANTS(M)
#undef M #undef M
@ -1183,32 +1370,12 @@ private:
Block res = result_sample_block.cloneEmpty(); Block res = result_sample_block.cloneEmpty();
/// @note it's possible to make ColumnConst here and materialize it later
for (size_t i = 0; i < columns_left.size(); ++i) for (size_t i = 0; i < columns_left.size(); ++i)
res.getByPosition(column_indices_left[i]).column = std::move(columns_left[i]); res.getByPosition(column_indices_left[i]).column = columns_left[i]->cloneResized(rows_added);
if (key_renames_indices.empty()) for (size_t i = 0; i < columns_keys_and_right.size(); ++i)
{ res.getByPosition(column_indices_keys_and_right[i]).column = std::move(columns_keys_and_right[i]);
for (size_t i = 0; i < columns_keys_and_right.size(); ++i)
res.getByPosition(column_indices_keys_and_right[i]).column = std::move(columns_keys_and_right[i]);
}
else
{
for (size_t i = 0; i < columns_keys_and_right.size(); ++i)
{
size_t key_idx = column_indices_keys_and_right[i];
auto it = key_renames_indices.find(key_idx);
if (it != key_renames_indices.end())
{
auto & key_column = res.getByPosition(key_idx).column;
if (key_column->empty())
key_column = key_column->cloneResized(columns_keys_and_right[i]->size());
res.getByPosition(it->second).column = std::move(columns_keys_and_right[i]);
}
else
res.getByPosition(key_idx).column = std::move(columns_keys_and_right[i]);
}
}
return res; return res;
} }
@ -1230,7 +1397,7 @@ private:
} }
template <ASTTableJoin::Strictness STRICTNESS, typename Map> template <ASTTableJoin::Strictness STRICTNESS, typename Map>
size_t fillColumns(const Map & map, MutableColumns & columns_left, MutableColumns & columns_keys_and_right) size_t fillColumns(const Map & map, MutableColumns & columns_keys_and_right)
{ {
size_t rows_added = 0; size_t rows_added = 0;
@ -1247,7 +1414,7 @@ private:
if (it->getSecond().getUsed()) if (it->getSecond().getUsed())
continue; continue;
AdderNonJoined<STRICTNESS, typename Map::mapped_type>::add(it->getSecond(), rows_added, columns_left, columns_keys_and_right); AdderNonJoined<STRICTNESS, typename Map::mapped_type>::add(it->getSecond(), rows_added, columns_keys_and_right);
if (rows_added >= max_block_size) if (rows_added >= max_block_size)
{ {

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <optional>
#include <shared_mutex> #include <shared_mutex>
#include <Parsers/ASTTablesInSelectQuery.h> #include <Parsers/ASTTablesInSelectQuery.h>
@ -150,6 +151,21 @@ public:
RowRefList(const Block * block_, size_t row_num_) : RowRef(block_, row_num_) {} RowRefList(const Block * block_, size_t row_num_) : RowRef(block_, row_num_) {}
}; };
/// Map for a time series
using ASOFTimeType = UInt32;
using AsofGetterType = ColumnsHashing::HashMethodOneNumber<ASOFTimeType, ASOFTimeType, ASOFTimeType, false>;
struct TSRowRef
{
// TODO use the arena allocator to get memory for this
// This would require ditching std::map because std::allocator is incompatible with the arena allocator
std::map<ASOFTimeType, RowRef> ts;
TSRowRef() {}
void insert(ASOFTimeType t, const Block * block, size_t row_num);
std::optional<std::pair<ASOFTimeType, RowRef>> findAsof(ASOFTimeType t) const;
std::string dumpStructure() const;
size_t size() const;
};
/** Depending on template parameter, adds or doesn't add a flag, that element was used (row was joined). /** Depending on template parameter, adds or doesn't add a flag, that element was used (row was joined).
* Depending on template parameter, decide whether to overwrite existing values when encountering the same key again * Depending on template parameter, decide whether to overwrite existing values when encountering the same key again
@ -181,7 +197,6 @@ public:
bool getUsed() const { return true; } bool getUsed() const { return true; }
}; };
/// Different types of keys for maps. /// Different types of keys for maps.
#define APPLY_FOR_JOIN_VARIANTS(M) \ #define APPLY_FOR_JOIN_VARIANTS(M) \
M(key8) \ M(key8) \
@ -282,6 +297,7 @@ public:
using MapsAnyFull = MapsTemplate<WithFlags<true, false, RowRef>>; using MapsAnyFull = MapsTemplate<WithFlags<true, false, RowRef>>;
using MapsAnyFullOverwrite = MapsTemplate<WithFlags<true, true, RowRef>>; using MapsAnyFullOverwrite = MapsTemplate<WithFlags<true, true, RowRef>>;
using MapsAllFull = MapsTemplate<WithFlags<true, false, RowRefList>>; using MapsAllFull = MapsTemplate<WithFlags<true, false, RowRefList>>;
using MapsAsof = MapsTemplate<WithFlags<false, false, TSRowRef>>;
template <ASTTableJoin::Kind KIND> template <ASTTableJoin::Kind KIND>
struct KindTrait struct KindTrait
@ -300,7 +316,7 @@ public:
template <ASTTableJoin::Kind kind, ASTTableJoin::Strictness strictness, bool overwrite> template <ASTTableJoin::Kind kind, ASTTableJoin::Strictness strictness, bool overwrite>
using Map = typename MapGetterImpl<KindTrait<kind>::fill_right, strictness, overwrite>::Map; using Map = typename MapGetterImpl<KindTrait<kind>::fill_right, strictness, overwrite>::Map;
static constexpr std::array<ASTTableJoin::Strictness, 2> STRICTNESSES = {ASTTableJoin::Strictness::Any, ASTTableJoin::Strictness::All}; static constexpr std::array<ASTTableJoin::Strictness, 3> STRICTNESSES = {ASTTableJoin::Strictness::Any, ASTTableJoin::Strictness::All, ASTTableJoin::Strictness::Asof};
static constexpr std::array<ASTTableJoin::Kind, 4> KINDS static constexpr std::array<ASTTableJoin::Kind, 4> KINDS
= {ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Inner, ASTTableJoin::Kind::Full, ASTTableJoin::Kind::Right}; = {ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Inner, ASTTableJoin::Kind::Full, ASTTableJoin::Kind::Right};
@ -377,7 +393,7 @@ private:
*/ */
BlocksList blocks; BlocksList blocks;
std::variant<MapsAny, MapsAnyOverwrite, MapsAll, MapsAnyFull, MapsAnyFullOverwrite, MapsAllFull> maps; std::variant<MapsAny, MapsAnyOverwrite, MapsAll, MapsAnyFull, MapsAnyFullOverwrite, MapsAllFull, MapsAsof> maps;
/// Additional data - strings for string keys and continuation elements of single-linked lists of references to rows. /// Additional data - strings for string keys and continuation elements of single-linked lists of references to rows.
Arena pool; Arena pool;
@ -454,4 +470,10 @@ struct Join::MapGetterImpl<true, ASTTableJoin::Strictness::All, false>
using Map = MapsAllFull; using Map = MapsAllFull;
}; };
template <bool fill_right>
struct Join::MapGetterImpl<fill_right, ASTTableJoin::Strictness::Asof, false>
{
using Map = MapsAsof;
};
} }

View File

@ -39,9 +39,13 @@ ASTPtr ASTColumnDeclaration::clone() const
void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void ASTColumnDeclaration::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {
frame.need_parens = false; frame.need_parens = false;
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
settings.ostr << settings.nl_or_ws << indent_str << backQuoteIfNeed(name); if (!settings.one_line)
settings.ostr << settings.nl_or_ws << std::string(4 * frame.indent, ' ');
/// We have to always backquote column names to avoid ambiguouty with INDEX and other declarations in CREATE query.
settings.ostr << backQuote(name);
if (type) if (type)
{ {
settings.ostr << ' '; settings.ostr << ' ';

View File

@ -145,6 +145,9 @@ void ASTTableJoin::formatImplBeforeTable(const FormatSettings & settings, Format
case Strictness::All: case Strictness::All:
settings.ostr << "ALL "; settings.ostr << "ALL ";
break; break;
case Strictness::Asof:
settings.ostr << "ASOF ";
break;
} }
} }

View File

@ -75,7 +75,8 @@ struct ASTTableJoin : public IAST
{ {
Unspecified, Unspecified,
Any, /// If there are many suitable rows to join, use any from them (also known as unique JOIN). Any, /// If there are many suitable rows to join, use any from them (also known as unique JOIN).
All /// If there are many suitable rows to join, use all of them and replicate rows of "left" table (usual semantic of JOIN). All, /// If there are many suitable rows to join, use all of them and replicate rows of "left" table (usual semantic of JOIN).
Asof, /// For the last JOIN column, pick the latest value
}; };
/// Join method. /// Join method.

View File

@ -1113,6 +1113,7 @@ const char * ParserAlias::restricted_keywords[] =
"INNER", "INNER",
"FULL", "FULL",
"CROSS", "CROSS",
"ASOF",
"JOIN", "JOIN",
"GLOBAL", "GLOBAL",
"ANY", "ANY",

View File

@ -25,7 +25,6 @@ const char * IAST::hilite_alias = "\033[0;32m";
const char * IAST::hilite_none = "\033[0m"; const char * IAST::hilite_none = "\033[0m";
/// Quote the identifier with backquotes, if required.
String backQuoteIfNeed(const String & x) String backQuoteIfNeed(const String & x)
{ {
String res(x.size(), '\0'); String res(x.size(), '\0');
@ -36,6 +35,16 @@ String backQuoteIfNeed(const String & x)
return res; return res;
} }
String backQuote(const String & x)
{
String res(x.size(), '\0');
{
WriteBufferFromString wb(res);
writeBackQuotedString(x, wb);
}
return res;
}
size_t IAST::checkSize(size_t max_size) const size_t IAST::checkSize(size_t max_size) const
{ {

View File

@ -208,7 +208,9 @@ private:
}; };
/// Surrounds an identifier by back quotes if it is necessary. /// Quote the identifier with backquotes, if required.
String backQuoteIfNeed(const String & x); String backQuoteIfNeed(const String & x);
/// Quote the identifier with backquotes.
String backQuote(const String & x);
} }

View File

@ -135,6 +135,8 @@ bool ParserTablesInSelectQueryElement::parseImpl(Pos & pos, ASTPtr & node, Expec
table_join->strictness = ASTTableJoin::Strictness::Any; table_join->strictness = ASTTableJoin::Strictness::Any;
else if (ParserKeyword("ALL").ignore(pos)) else if (ParserKeyword("ALL").ignore(pos))
table_join->strictness = ASTTableJoin::Strictness::All; table_join->strictness = ASTTableJoin::Strictness::All;
else if (ParserKeyword("ASOF").ignore(pos))
table_join->strictness = ASTTableJoin::Strictness::Asof;
else else
table_join->strictness = ASTTableJoin::Strictness::Unspecified; table_join->strictness = ASTTableJoin::Strictness::Unspecified;

View File

@ -611,7 +611,7 @@ String MergeTreeData::MergingParams::getModeName() const
Int64 MergeTreeData::getMaxBlockNumber() Int64 MergeTreeData::getMaxBlockNumber()
{ {
std::lock_guard lock_all(data_parts_mutex); auto lock = lockParts();
Int64 max_block_num = 0; Int64 max_block_num = 0;
for (const DataPartPtr & part : data_parts_by_info) for (const DataPartPtr & part : data_parts_by_info)
@ -640,7 +640,7 @@ void MergeTreeData::loadDataParts(bool skip_sanity_checks)
DataPartsVector broken_parts_to_detach; DataPartsVector broken_parts_to_detach;
size_t suspicious_broken_parts = 0; size_t suspicious_broken_parts = 0;
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
data_parts_indexes.clear(); data_parts_indexes.clear();
for (const String & file_name : part_file_names) for (const String & file_name : part_file_names)
@ -866,7 +866,7 @@ MergeTreeData::DataPartsVector MergeTreeData::grabOldParts()
std::vector<DataPartIteratorByStateAndInfo> parts_to_delete; std::vector<DataPartIteratorByStateAndInfo> parts_to_delete;
{ {
std::lock_guard lock_parts(data_parts_mutex); auto parts_lock = lockParts();
auto outdated_parts_range = getDataPartsStateRange(DataPartState::Outdated); auto outdated_parts_range = getDataPartsStateRange(DataPartState::Outdated);
for (auto it = outdated_parts_range.begin(); it != outdated_parts_range.end(); ++it) for (auto it = outdated_parts_range.begin(); it != outdated_parts_range.end(); ++it)
@ -900,7 +900,7 @@ MergeTreeData::DataPartsVector MergeTreeData::grabOldParts()
void MergeTreeData::rollbackDeletingParts(const MergeTreeData::DataPartsVector & parts) void MergeTreeData::rollbackDeletingParts(const MergeTreeData::DataPartsVector & parts)
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
for (auto & part : parts) for (auto & part : parts)
{ {
/// We should modify it under data_parts_mutex /// We should modify it under data_parts_mutex
@ -912,7 +912,7 @@ void MergeTreeData::rollbackDeletingParts(const MergeTreeData::DataPartsVector &
void MergeTreeData::removePartsFinally(const MergeTreeData::DataPartsVector & parts) void MergeTreeData::removePartsFinally(const MergeTreeData::DataPartsVector & parts)
{ {
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
/// TODO: use data_parts iterators instead of pointers /// TODO: use data_parts iterators instead of pointers
for (auto & part : parts) for (auto & part : parts)
@ -980,7 +980,7 @@ void MergeTreeData::dropAllData()
{ {
LOG_TRACE(log, "dropAllData: waiting for locks."); LOG_TRACE(log, "dropAllData: waiting for locks.");
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
LOG_TRACE(log, "dropAllData: removing data from memory."); LOG_TRACE(log, "dropAllData: removing data from memory.");
@ -1717,7 +1717,7 @@ MergeTreeData::DataPartsVector MergeTreeData::renameTempPartAndReplace(
DataPartsVector covered_parts; DataPartsVector covered_parts;
{ {
std::unique_lock lock(data_parts_mutex); auto lock = lockParts();
renameTempPartAndReplace(part, increment, out_transaction, lock, &covered_parts); renameTempPartAndReplace(part, increment, out_transaction, lock, &covered_parts);
} }
return covered_parts; return covered_parts;
@ -1814,7 +1814,7 @@ restore_covered)
{ {
LOG_INFO(log, "Renaming " << part_to_detach->relative_path << " to " << prefix << part_to_detach->name << " and forgiving it."); LOG_INFO(log, "Renaming " << part_to_detach->relative_path << " to " << prefix << part_to_detach->name << " and forgiving it.");
auto data_parts_lock = lockParts(); auto lock = lockParts();
auto it_part = data_parts_by_info.find(part_to_detach->info); auto it_part = data_parts_by_info.find(part_to_detach->info);
if (it_part == data_parts_by_info.end()) if (it_part == data_parts_by_info.end())
@ -1931,7 +1931,7 @@ void MergeTreeData::tryRemovePartImmediately(DataPartPtr && part)
{ {
DataPartPtr part_to_delete; DataPartPtr part_to_delete;
{ {
std::lock_guard lock_parts(data_parts_mutex); auto lock = lockParts();
LOG_TRACE(log, "Trying to immediately remove part " << part->getNameWithState()); LOG_TRACE(log, "Trying to immediately remove part " << part->getNameWithState());
@ -1967,7 +1967,7 @@ size_t MergeTreeData::getTotalActiveSizeInBytes() const
{ {
size_t res = 0; size_t res = 0;
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
for (auto & part : getDataPartsStateRange(DataPartState::Committed)) for (auto & part : getDataPartsStateRange(DataPartState::Committed))
res += part->bytes_on_disk; res += part->bytes_on_disk;
@ -1979,7 +1979,7 @@ size_t MergeTreeData::getTotalActiveSizeInBytes() const
size_t MergeTreeData::getMaxPartsCountForPartition() const size_t MergeTreeData::getMaxPartsCountForPartition() const
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
size_t res = 0; size_t res = 0;
size_t cur_count = 0; size_t cur_count = 0;
@ -2006,7 +2006,7 @@ size_t MergeTreeData::getMaxPartsCountForPartition() const
std::optional<Int64> MergeTreeData::getMinPartDataVersion() const std::optional<Int64> MergeTreeData::getMinPartDataVersion() const
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
std::optional<Int64> result; std::optional<Int64> result;
for (const DataPartPtr & part : getDataPartsStateRange(DataPartState::Committed)) for (const DataPartPtr & part : getDataPartsStateRange(DataPartState::Committed))
@ -2088,8 +2088,8 @@ MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(
MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(const MergeTreePartInfo & part_info) MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(const MergeTreePartInfo & part_info)
{ {
DataPartsLock data_parts_lock(data_parts_mutex); auto lock = lockParts();
return getActiveContainingPart(part_info, DataPartState::Committed, data_parts_lock); return getActiveContainingPart(part_info, DataPartState::Committed, lock);
} }
MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(const String & part_name) MergeTreeData::DataPartPtr MergeTreeData::getActiveContainingPart(const String & part_name)
@ -2103,7 +2103,7 @@ MergeTreeData::DataPartsVector MergeTreeData::getDataPartsVectorInPartition(Merg
{ {
DataPartStateAndPartitionID state_with_partition{state, partition_id}; DataPartStateAndPartitionID state_with_partition{state, partition_id};
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
return DataPartsVector( return DataPartsVector(
data_parts_by_state_and_info.lower_bound(state_with_partition), data_parts_by_state_and_info.lower_bound(state_with_partition),
data_parts_by_state_and_info.upper_bound(state_with_partition)); data_parts_by_state_and_info.upper_bound(state_with_partition));
@ -2112,7 +2112,7 @@ MergeTreeData::DataPartsVector MergeTreeData::getDataPartsVectorInPartition(Merg
MergeTreeData::DataPartPtr MergeTreeData::getPartIfExists(const MergeTreePartInfo & part_info, const MergeTreeData::DataPartStates & valid_states) MergeTreeData::DataPartPtr MergeTreeData::getPartIfExists(const MergeTreePartInfo & part_info, const MergeTreeData::DataPartStates & valid_states)
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
auto it = data_parts_by_info.find(part_info); auto it = data_parts_by_info.find(part_info);
if (it == data_parts_by_info.end()) if (it == data_parts_by_info.end())
@ -2248,30 +2248,6 @@ void MergeTreeData::freezePartition(const ASTPtr & partition_ast, const String &
context); context);
} }
size_t MergeTreeData::getPartitionSize(const std::string & partition_id) const
{
size_t size = 0;
Poco::DirectoryIterator end;
for (Poco::DirectoryIterator it(full_path); it != end; ++it)
{
MergeTreePartInfo part_info;
if (!MergeTreePartInfo::tryParsePartName(it.name(), &part_info, format_version))
continue;
if (part_info.partition_id != partition_id)
continue;
const auto part_path = it.path().absolute().toString();
for (Poco::DirectoryIterator it2(part_path); it2 != end; ++it2)
{
const auto part_file_path = it2.path().absolute().toString();
size += Poco::File(part_file_path).getSize();
}
}
return size;
}
String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, const Context & context) String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, const Context & context)
{ {
@ -2331,7 +2307,7 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, const Context
String partition_id = partition.getID(*this); String partition_id = partition.getID(*this);
{ {
DataPartsLock data_parts_lock(data_parts_mutex); auto data_parts_lock = lockParts();
DataPartPtr existing_part_in_partition = getAnyPartInPartition(partition_id, data_parts_lock); DataPartPtr existing_part_in_partition = getAnyPartInPartition(partition_id, data_parts_lock);
if (existing_part_in_partition && existing_part_in_partition->partition.value != partition.value) if (existing_part_in_partition && existing_part_in_partition->partition.value != partition.value)
{ {
@ -2352,7 +2328,7 @@ MergeTreeData::DataPartsVector MergeTreeData::getDataPartsVector(const DataPartS
DataPartsVector res; DataPartsVector res;
DataPartsVector buf; DataPartsVector buf;
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
for (auto state : affordable_states) for (auto state : affordable_states)
{ {
@ -2378,7 +2354,7 @@ MergeTreeData::DataPartsVector MergeTreeData::getAllDataPartsVector(MergeTreeDat
{ {
DataPartsVector res; DataPartsVector res;
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
res.assign(data_parts_by_info.begin(), data_parts_by_info.end()); res.assign(data_parts_by_info.begin(), data_parts_by_info.end());
if (out_states != nullptr) if (out_states != nullptr)
@ -2396,7 +2372,7 @@ MergeTreeData::DataParts MergeTreeData::getDataParts(const DataPartStates & affo
{ {
DataParts res; DataParts res;
{ {
std::lock_guard lock(data_parts_mutex); auto lock = lockParts();
for (auto state : affordable_states) for (auto state : affordable_states)
{ {
auto range = getDataPartsStateRange(state); auto range = getDataPartsStateRange(state);

View File

@ -533,13 +533,9 @@ public:
*/ */
void freezePartition(const ASTPtr & partition, const String & with_name, const Context & context); void freezePartition(const ASTPtr & partition, const String & with_name, const Context & context);
/// Returns the size of partition in bytes.
size_t getPartitionSize(const std::string & partition_id) const;
size_t getColumnCompressedSize(const std::string & name) const size_t getColumnCompressedSize(const std::string & name) const
{ {
std::lock_guard lock{data_parts_mutex}; auto lock = lockParts();
const auto it = column_sizes.find(name); const auto it = column_sizes.find(name);
return it == std::end(column_sizes) ? 0 : it->second.data_compressed; return it == std::end(column_sizes) ? 0 : it->second.data_compressed;
} }
@ -547,14 +543,14 @@ public:
using ColumnSizeByName = std::unordered_map<std::string, DataPart::ColumnSize>; using ColumnSizeByName = std::unordered_map<std::string, DataPart::ColumnSize>;
ColumnSizeByName getColumnSizes() const ColumnSizeByName getColumnSizes() const
{ {
std::lock_guard lock{data_parts_mutex}; auto lock = lockParts();
return column_sizes; return column_sizes;
} }
/// Calculates column sizes in compressed form for the current state of data_parts. /// Calculates column sizes in compressed form for the current state of data_parts.
void recalculateColumnSizes() void recalculateColumnSizes()
{ {
std::lock_guard lock{data_parts_mutex}; auto lock = lockParts();
calculateColumnSizesImpl(); calculateColumnSizesImpl();
} }

View File

@ -295,7 +295,7 @@ private:
if (column_with_null[i]) if (column_with_null[i])
{ {
if (key_pos == i) if (key_pos == i)
res.getByPosition(i).column = makeNullable(std::move(columns[i]))->assumeMutable(); res.getByPosition(i).column = makeNullable(std::move(columns[i]));
else else
{ {
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*columns[i]); const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(*columns[i]);
@ -333,6 +333,10 @@ private:
columns[j]->insertFrom(*it->getSecond().block->getByPosition(column_indices[j]).column.get(), it->getSecond().row_num); columns[j]->insertFrom(*it->getSecond().block->getByPosition(column_indices[j]).column.get(), it->getSecond().row_num);
++rows_added; ++rows_added;
} }
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
{
throw Exception("ASOF join storage is not implemented yet", ErrorCodes::NOT_IMPLEMENTED);
}
else else
for (auto current = &static_cast<const typename Map::mapped_type::Base_t &>(it->getSecond()); current != nullptr; for (auto current = &static_cast<const typename Map::mapped_type::Base_t &>(it->getSecond()); current != nullptr;
current = current->next) current = current->next)

View File

@ -2655,7 +2655,7 @@ bool StorageReplicatedMergeTree::fetchPart(const String & part_name, const Strin
if (auto part = data.getPartIfExists(part_info, {MergeTreeDataPart::State::Outdated, MergeTreeDataPart::State::Deleting})) if (auto part = data.getPartIfExists(part_info, {MergeTreeDataPart::State::Outdated, MergeTreeDataPart::State::Deleting}))
{ {
LOG_DEBUG(log, "Part " << part->getNameWithState() << " should be deleted after previous attempt before fetch"); LOG_DEBUG(log, "Part " << part->name << " should be deleted after previous attempt before fetch");
/// Force immediate parts cleanup to delete the part that was left from the previous fetch attempt. /// Force immediate parts cleanup to delete the part that was left from the previous fetch attempt.
cleanup_thread.wakeup(); cleanup_thread.wakeup();
return false; return false;

View File

@ -21,6 +21,7 @@ namespace DB
namespace ErrorCodes namespace ErrorCodes
{ {
extern const int CANNOT_GET_CREATE_TABLE_QUERY; extern const int CANNOT_GET_CREATE_TABLE_QUERY;
extern const int TABLE_IS_DROPPED;
} }
@ -174,9 +175,20 @@ protected:
for (; rows_count < max_block_size && tables_it->isValid(); tables_it->next()) for (; rows_count < max_block_size && tables_it->isValid(); tables_it->next())
{ {
auto table_name = tables_it->name(); auto table_name = tables_it->name();
const auto table = context.tryGetTable(database_name, table_name); const StoragePtr & table = tables_it->table();
if (!table)
continue; TableStructureReadLockHolder lock;
try
{
lock = table->lockStructureForShare(false, context.getCurrentQueryId());
}
catch (const Exception & e)
{
if (e.code() == ErrorCodes::TABLE_IS_DROPPED)
continue;
throw;
}
++rows_count; ++rows_count;
@ -190,13 +202,13 @@ protected:
res_columns[res_index++]->insert(table_name); res_columns[res_index++]->insert(table_name);
if (columns_mask[src_index++]) if (columns_mask[src_index++])
res_columns[res_index++]->insert(tables_it->table()->getName()); res_columns[res_index++]->insert(table->getName());
if (columns_mask[src_index++]) if (columns_mask[src_index++])
res_columns[res_index++]->insert(0u); // is_temporary res_columns[res_index++]->insert(0u); // is_temporary
if (columns_mask[src_index++]) if (columns_mask[src_index++])
res_columns[res_index++]->insert(tables_it->table()->getDataPath()); res_columns[res_index++]->insert(table->getDataPath());
if (columns_mask[src_index++]) if (columns_mask[src_index++])
res_columns[res_index++]->insert(database->getTableMetadataPath(table_name)); res_columns[res_index++]->insert(database->getTableMetadataPath(table_name));

View File

@ -31,6 +31,7 @@ MSG_OK = OP_SQUARE_BRACKET + colored(" OK ", "green", attrs=['bold']) + CL_SQUAR
MSG_SKIPPED = OP_SQUARE_BRACKET + colored(" SKIPPED ", "cyan", attrs=['bold']) + CL_SQUARE_BRACKET MSG_SKIPPED = OP_SQUARE_BRACKET + colored(" SKIPPED ", "cyan", attrs=['bold']) + CL_SQUARE_BRACKET
MESSAGES_TO_RETRY = [ MESSAGES_TO_RETRY = [
"DB::Exception: ZooKeeper session has been expired",
"Coordination::Exception: Connection loss", "Coordination::Exception: Connection loss",
] ]

View File

@ -53,6 +53,13 @@
<query><![CDATA[SELECT count() FROM hits_100m_single WHERE multiMatchAny(URL, ['chelyabinsk\\.74\\.ru', 'doctor\\.74\\.ru', 'transport\\.74\\.ru', 'm\\.74\\.ru', '//74\\.ru/', 'chel\\.74\\.ru', 'afisha\\.74\\.ru', 'diplom\\.74\\.ru', 'chelfin\\.ru', '//chel\\.ru', 'chelyabinsk\\.ru', 'cheldoctor\\.ru', '//mychel\\.ru', 'cheldiplom\\.ru', '74\\.ru/video', 'market', 'poll', 'mail', 'conference', 'consult', 'contest', 'tags', 'feedback', 'pages', 'text'])]]></query> <query><![CDATA[SELECT count() FROM hits_100m_single WHERE multiMatchAny(URL, ['chelyabinsk\\.74\\.ru', 'doctor\\.74\\.ru', 'transport\\.74\\.ru', 'm\\.74\\.ru', '//74\\.ru/', 'chel\\.74\\.ru', 'afisha\\.74\\.ru', 'diplom\\.74\\.ru', 'chelfin\\.ru', '//chel\\.ru', 'chelyabinsk\\.ru', 'cheldoctor\\.ru', '//mychel\\.ru', 'cheldiplom\\.ru', '74\\.ru/video', 'market', 'poll', 'mail', 'conference', 'consult', 'contest', 'tags', 'feedback', 'pages', 'text'])]]></query>
<query><![CDATA[SELECT count() FROM hits_100m_single WHERE multiSearchAny(URL, ['chelyabinsk.74.ru', 'doctor.74.ru', 'transport.74.ru', 'm.74.ru', '//74.ru/', 'chel.74.ru', 'afisha.74.ru', 'diplom.74.ru', 'chelfin.ru', '//chel.ru', 'chelyabinsk.ru', 'cheldoctor.ru', '//mychel.ru', 'cheldiplom.ru', '74.ru/video', 'market', 'poll', 'mail', 'conference', 'consult', 'contest', 'tags', 'feedback', 'pages', 'text'])]]></query> <query><![CDATA[SELECT count() FROM hits_100m_single WHERE multiSearchAny(URL, ['chelyabinsk.74.ru', 'doctor.74.ru', 'transport.74.ru', 'm.74.ru', '//74.ru/', 'chel.74.ru', 'afisha.74.ru', 'diplom.74.ru', 'chelfin.ru', '//chel.ru', 'chelyabinsk.ru', 'cheldoctor.ru', '//mychel.ru', 'cheldiplom.ru', '74.ru/video', 'market', 'poll', 'mail', 'conference', 'consult', 'contest', 'tags', 'feedback', 'pages', 'text'])]]></query>
<query><![CDATA[SELECT DISTINCT Title, multiFuzzyMatchAny(Title, 2, ['^metrika\\.ry$']) AS distance FROM hits_100m_single WHERE distance = 1]]></query>
<query><![CDATA[SELECT DISTINCT Title, multiFuzzyMatchAny(Title, 5, ['^metrika\\.ry$']) AS distance FROM hits_100m_single WHERE distance = 1]]></query>
<query><![CDATA[SELECT sum(multiFuzzyMatchAny(Title, 3, ['hello$', 'world$', '^hello'])) FROM hits_100m_single]]></query>
<query><![CDATA[SELECT count() FROM hits_100m_single WHERE multiFuzzyMatchAny(URL, 2, ['about/address', 'for_woman', '^https?://lm-company.ruy/$', 'ultimateguitar.com'])]]></query>
<main_metric> <main_metric>
<min_time/> <min_time/>

View File

@ -1,14 +1,14 @@
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32) ENGINE = MergeTree(d, k, 8192)
2015-01-01 10 42 2015-01-01 10 42
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, `n.ui8` Array(UInt8), `n.s` Array(String)) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `n.ui8` Array(UInt8), `n.s` Array(String)) ENGINE = MergeTree(d, k, 8192)
2015-01-01 8 40 [1,2,3] ['12','13','14'] 2015-01-01 8 40 [1,2,3] ['12','13','14']
2015-01-01 10 42 [] [] 2015-01-01 10 42 [] []
d Date d Date
@ -17,7 +17,7 @@ i32 Int32
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date)) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date)) ENGINE = MergeTree(d, k, 8192)
2015-01-01 7 39 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03'] 2015-01-01 7 39 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03']
2015-01-01 8 40 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 8 40 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00']
2015-01-01 10 42 [] [] [] 2015-01-01 10 42 [] [] []
@ -28,7 +28,7 @@ n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
s String DEFAULT \'0\' s String DEFAULT \'0\'
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date), s String DEFAULT \'0\') ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date), `s` String DEFAULT \'0\') ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 [10,20,30] ['asd','qwe','qwe'] ['2000-01-01','2000-01-01','2000-01-03'] 100500 2015-01-01 6 38 [10,20,30] ['asd','qwe','qwe'] ['2000-01-01','2000-01-01','2000-01-03'] 100500
2015-01-01 7 39 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03'] 0 2015-01-01 7 39 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03'] 0
2015-01-01 8 40 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00'] 0 2015-01-01 8 40 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00'] 0
@ -39,7 +39,7 @@ i32 Int32
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
s Int64 s Int64
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, `n.ui8` Array(UInt8), `n.s` Array(String), s Int64) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `n.ui8` Array(UInt8), `n.s` Array(String), `s` Int64) ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 [10,20,30] ['asd','qwe','qwe'] 100500 2015-01-01 6 38 [10,20,30] ['asd','qwe','qwe'] 100500
2015-01-01 7 39 [10,20,30] ['120','130','140'] 0 2015-01-01 7 39 [10,20,30] ['120','130','140'] 0
2015-01-01 8 40 [1,2,3] ['12','13','14'] 0 2015-01-01 8 40 [1,2,3] ['12','13','14'] 0
@ -51,7 +51,7 @@ n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
s UInt32 s UInt32
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, `n.ui8` Array(UInt8), `n.s` Array(String), s UInt32, `n.d` Array(Date)) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `n.ui8` Array(UInt8), `n.s` Array(String), `s` UInt32, `n.d` Array(Date)) ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 [10,20,30] ['asd','qwe','qwe'] 100500 ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 6 38 [10,20,30] ['asd','qwe','qwe'] 100500 ['0000-00-00','0000-00-00','0000-00-00']
2015-01-01 7 39 [10,20,30] ['120','130','140'] 0 ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 7 39 [10,20,30] ['120','130','140'] 0 ['0000-00-00','0000-00-00','0000-00-00']
2015-01-01 8 40 [1,2,3] ['12','13','14'] 0 ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 8 40 [1,2,3] ['12','13','14'] 0 ['0000-00-00','0000-00-00','0000-00-00']
@ -65,7 +65,7 @@ k UInt64
i32 Int32 i32 Int32
n.s Array(String) n.s Array(String)
s UInt32 s UInt32
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, `n.s` Array(String), s UInt32) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `n.s` Array(String), `s` UInt32) ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 ['asd','qwe','qwe'] 100500 2015-01-01 6 38 ['asd','qwe','qwe'] 100500
2015-01-01 7 39 ['120','130','140'] 0 2015-01-01 7 39 ['120','130','140'] 0
2015-01-01 8 40 ['12','13','14'] 0 2015-01-01 8 40 ['12','13','14'] 0
@ -74,7 +74,7 @@ d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
s UInt32 s UInt32
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, s UInt32) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `s` UInt32) ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 100500 2015-01-01 6 38 100500
2015-01-01 7 39 0 2015-01-01 7 39 0
2015-01-01 8 40 0 2015-01-01 8 40 0
@ -85,7 +85,7 @@ i32 Int32
s UInt32 s UInt32
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, s UInt32, `n.s` Array(String), `n.d` Array(Date)) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `s` UInt32, `n.s` Array(String), `n.d` Array(Date)) ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 100500 [] [] 2015-01-01 6 38 100500 [] []
2015-01-01 7 39 0 [] [] 2015-01-01 7 39 0 [] []
2015-01-01 8 40 0 [] [] 2015-01-01 8 40 0 [] []
@ -94,7 +94,7 @@ d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
s UInt32 s UInt32
CREATE TABLE test.alter ( d Date, k UInt64, i32 Int32, s UInt32) ENGINE = MergeTree(d, k, 8192) CREATE TABLE test.alter (`d` Date, `k` UInt64, `i32` Int32, `s` UInt32) ENGINE = MergeTree(d, k, 8192)
2015-01-01 6 38 100500 2015-01-01 6 38 100500
2015-01-01 7 39 0 2015-01-01 7 39 0
2015-01-01 8 40 0 2015-01-01 8 40 0

View File

@ -1,22 +1,22 @@
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 10 42 2015-01-01 10 42
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 9 41 1992-01-01 08:00:00 2015-01-01 9 41 1992-01-01 08:00:00
2015-01-01 10 42 0000-00-00 00:00:00 2015-01-01 10 42 0000-00-00 00:00:00
d Date d Date
@ -25,14 +25,14 @@ i32 Int32
dt DateTime dt DateTime
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] 2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14']
2015-01-01 9 41 1992-01-01 08:00:00 [] [] 2015-01-01 9 41 1992-01-01 08:00:00 [] []
2015-01-01 10 42 0000-00-00 00:00:00 [] [] 2015-01-01 10 42 0000-00-00 00:00:00 [] []
@ -43,7 +43,7 @@ dt DateTime
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
@ -51,7 +51,7 @@ dt DateTime
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03'] 2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03']
2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00']
2015-01-01 9 41 1992-01-01 08:00:00 [] [] [] 2015-01-01 9 41 1992-01-01 08:00:00 [] [] []
@ -64,7 +64,7 @@ n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
s String DEFAULT \'0\' s String DEFAULT \'0\'
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date), s String DEFAULT \'0\') ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date), `s` String DEFAULT \'0\') ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
@ -73,7 +73,7 @@ n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
s String DEFAULT \'0\' s String DEFAULT \'0\'
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date), s String DEFAULT \'0\') ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `n.d` Array(Date), `s` String DEFAULT \'0\') ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 [10,20,30] ['asd','qwe','qwe'] ['2000-01-01','2000-01-01','2000-01-03'] 100500 2015-01-01 6 38 2014-07-15 13:26:50 [10,20,30] ['asd','qwe','qwe'] ['2000-01-01','2000-01-01','2000-01-03'] 100500
2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03'] 0 2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] ['2000-01-01','2000-01-01','2000-01-03'] 0
2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00'] 0 2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] ['0000-00-00','0000-00-00','0000-00-00'] 0
@ -86,7 +86,7 @@ dt DateTime
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
s Int64 s Int64
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), s Int64) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `s` Int64) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
@ -94,7 +94,7 @@ dt DateTime
n.ui8 Array(UInt8) n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
s Int64 s Int64
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), s Int64) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `s` Int64) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 [10,20,30] ['asd','qwe','qwe'] 100500 2015-01-01 6 38 2014-07-15 13:26:50 [10,20,30] ['asd','qwe','qwe'] 100500
2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] 0 2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] 0
2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] 0 2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] 0
@ -108,7 +108,7 @@ n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
s UInt32 s UInt32
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), s UInt32, `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `s` UInt32, `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
@ -117,7 +117,7 @@ n.ui8 Array(UInt8)
n.s Array(String) n.s Array(String)
s UInt32 s UInt32
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), s UInt32, `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.ui8` Array(UInt8), `n.s` Array(String), `s` UInt32, `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 [10,20,30] ['asd','qwe','qwe'] 100500 ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 6 38 2014-07-15 13:26:50 [10,20,30] ['asd','qwe','qwe'] 100500 ['0000-00-00','0000-00-00','0000-00-00']
2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] 0 ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 7 39 2014-07-14 13:26:50 [10,20,30] ['120','130','140'] 0 ['0000-00-00','0000-00-00','0000-00-00']
2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] 0 ['0000-00-00','0000-00-00','0000-00-00'] 2015-01-01 8 40 2012-12-12 12:12:12 [1,2,3] ['12','13','14'] 0 ['0000-00-00','0000-00-00','0000-00-00']
@ -129,14 +129,14 @@ i32 Int32
dt DateTime dt DateTime
n.s Array(String) n.s Array(String)
s UInt32 s UInt32
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.s` Array(String), s UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.s` Array(String), `s` UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
n.s Array(String) n.s Array(String)
s UInt32 s UInt32
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, `n.s` Array(String), s UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `n.s` Array(String), `s` UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 ['asd','qwe','qwe'] 100500 2015-01-01 6 38 2014-07-15 13:26:50 ['asd','qwe','qwe'] 100500
2015-01-01 7 39 2014-07-14 13:26:50 ['120','130','140'] 0 2015-01-01 7 39 2014-07-14 13:26:50 ['120','130','140'] 0
2015-01-01 8 40 2012-12-12 12:12:12 ['12','13','14'] 0 2015-01-01 8 40 2012-12-12 12:12:12 ['12','13','14'] 0
@ -147,13 +147,13 @@ k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
s UInt32 s UInt32
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, s UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `s` UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
s UInt32 s UInt32
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, s UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `s` UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 100500 2015-01-01 6 38 2014-07-15 13:26:50 100500
2015-01-01 7 39 2014-07-14 13:26:50 0 2015-01-01 7 39 2014-07-14 13:26:50 0
2015-01-01 8 40 2012-12-12 12:12:12 0 2015-01-01 8 40 2012-12-12 12:12:12 0
@ -166,7 +166,7 @@ dt DateTime
s UInt32 s UInt32
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, s UInt32, `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `s` UInt32, `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
@ -174,7 +174,7 @@ dt DateTime
s UInt32 s UInt32
n.s Array(String) n.s Array(String)
n.d Array(Date) n.d Array(Date)
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, s UInt32, `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `s` UInt32, `n.s` Array(String), `n.d` Array(Date)) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 100500 [] [] 2015-01-01 6 38 2014-07-15 13:26:50 100500 [] []
2015-01-01 7 39 2014-07-14 13:26:50 0 [] [] 2015-01-01 7 39 2014-07-14 13:26:50 0 [] []
2015-01-01 8 40 2012-12-12 12:12:12 0 [] [] 2015-01-01 8 40 2012-12-12 12:12:12 0 [] []
@ -185,13 +185,13 @@ k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
s UInt32 s UInt32
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt DateTime, s UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `s` UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt DateTime dt DateTime
s UInt32 s UInt32
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt DateTime, s UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` DateTime, `s` UInt32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 13:26:50 100500 2015-01-01 6 38 2014-07-15 13:26:50 100500
2015-01-01 7 39 2014-07-14 13:26:50 0 2015-01-01 7 39 2014-07-14 13:26:50 0
2015-01-01 8 40 2012-12-12 12:12:12 0 2015-01-01 8 40 2012-12-12 12:12:12 0
@ -202,13 +202,13 @@ k UInt64
i32 Int32 i32 Int32
dt Date dt Date
s DateTime s DateTime
CREATE TABLE test.replicated_alter1 ( d Date, k UInt64, i32 Int32, dt Date, s DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192) CREATE TABLE test.replicated_alter1 (`d` Date, `k` UInt64, `i32` Int32, `dt` Date, `s` DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r1\', d, k, 8192)
d Date d Date
k UInt64 k UInt64
i32 Int32 i32 Int32
dt Date dt Date
s DateTime s DateTime
CREATE TABLE test.replicated_alter2 ( d Date, k UInt64, i32 Int32, dt Date, s DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192) CREATE TABLE test.replicated_alter2 (`d` Date, `k` UInt64, `i32` Int32, `dt` Date, `s` DateTime) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/alter\', \'r2\', d, k, 8192)
2015-01-01 6 38 2014-07-15 1970-01-02 06:55:00 2015-01-01 6 38 2014-07-15 1970-01-02 06:55:00
2015-01-01 7 39 2014-07-14 0000-00-00 00:00:00 2015-01-01 7 39 2014-07-14 0000-00-00 00:00:00
2015-01-01 8 40 2012-12-12 0000-00-00 00:00:00 2015-01-01 8 40 2012-12-12 0000-00-00 00:00:00

View File

@ -1,7 +1,7 @@
A A
B B
A 1 TinyLog CREATE TABLE test_show_tables.A ( A UInt8) ENGINE = TinyLog A 1 TinyLog CREATE TABLE test_show_tables.A (`A` UInt8) ENGINE = TinyLog
B 1 TinyLog CREATE TABLE test_show_tables.B ( A UInt8) ENGINE = TinyLog B 1 TinyLog CREATE TABLE test_show_tables.B (`A` UInt8) ENGINE = TinyLog
test_temporary_table test_temporary_table
['test_show_tables'] ['test_materialized'] ['test_show_tables'] ['test_materialized']
0 0

View File

@ -23432,3 +23432,7 @@
1 1
1 1
1 1
1
1
1
1

View File

@ -1,3 +1,4 @@
SET send_logs_level = 'none';
select 1 = position('', ''); select 1 = position('', '');
select 1 = position('abc', ''); select 1 = position('abc', '');
select 0 = position('', 'abc'); select 0 = position('', 'abc');
@ -1462,3 +1463,87 @@ select 0 = multiSearchAny(materialize('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab',
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab',
'b']); 'b']);
-- 254
select
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
] =
multiSearchAllPositions(materialize('string'),
['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'str']);
select 254 = multiSearchFirstIndex(materialize('string'),
['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'str']);
select
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
] =
multiSearchAllPositions(materialize('string'),
['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'str']);
select 255 = multiSearchFirstIndex(materialize('string'),
['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'str']);
select multiSearchAllPositions(materialize('string'),
['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'str']); -- { serverError 42 }
select multiSearchFirstIndex(materialize('string'),
['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o',
'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'str']); -- { serverError 42 }

View File

@ -1,4 +1,4 @@
1 1
CREATE TEMPORARY TABLE temp_tab ( number UInt64) ENGINE = Memory CREATE TEMPORARY TABLE temp_tab (`number` UInt64) ENGINE = Memory
temp_tab temp_tab
0 0

View File

@ -1 +1 @@
CREATE VIEW test.test_view ( id UInt64) AS SELECT * FROM test.test WHERE id = (SELECT 1) CREATE VIEW test.test_view (`id` UInt64) AS SELECT * FROM test.test WHERE id = (SELECT 1)

View File

@ -7,7 +7,7 @@ hello
hello hello
hello hello
1970-01-01 00:00:01 1970-01-01 00:00:01
CREATE TABLE test.cast ( x UInt8, e Enum8('hello' = 1, 'world' = 2) DEFAULT CAST(x, 'Enum8(\'hello\' = 1, \'world\' = 2)')) ENGINE = MergeTree ORDER BY e SETTINGS index_granularity = 8192 CREATE TABLE test.cast (`x` UInt8, `e` Enum8('hello' = 1, 'world' = 2) DEFAULT CAST(x, 'Enum8(\'hello\' = 1, \'world\' = 2)')) ENGINE = MergeTree ORDER BY e SETTINGS index_granularity = 8192
x UInt8 x UInt8
e Enum8(\'hello\' = 1, \'world\' = 2) DEFAULT CAST(x, \'Enum8(\\\'hello\\\' = 1, \\\'world\\\' = 2)\') e Enum8(\'hello\' = 1, \'world\' = 2) DEFAULT CAST(x, \'Enum8(\\\'hello\\\' = 1, \\\'world\\\' = 2)\')
1 hello 1 hello

View File

@ -1,4 +1,4 @@
CREATE TABLE test.cast1 ( x UInt8, e Enum8('hello' = 1, 'world' = 2) DEFAULT CAST(x, 'Enum8(\'hello\' = 1, \'world\' = 2)')) ENGINE = ReplicatedMergeTree('/clickhouse/tables/test_cast', 'r1') ORDER BY e SETTINGS index_granularity = 8192 CREATE TABLE test.cast1 (`x` UInt8, `e` Enum8('hello' = 1, 'world' = 2) DEFAULT CAST(x, 'Enum8(\'hello\' = 1, \'world\' = 2)')) ENGINE = ReplicatedMergeTree('/clickhouse/tables/test_cast', 'r1') ORDER BY e SETTINGS index_granularity = 8192
x UInt8 x UInt8
e Enum8(\'hello\' = 1, \'world\' = 2) DEFAULT CAST(x, \'Enum8(\\\'hello\\\' = 1, \\\'world\\\' = 2)\') e Enum8(\'hello\' = 1, \'world\' = 2) DEFAULT CAST(x, \'Enum8(\\\'hello\\\' = 1, \\\'world\\\' = 2)\')
1 hello 1 hello

View File

@ -1,4 +1,4 @@
CREATE TABLE test.check_query_comment_column ( first_column UInt8 DEFAULT 1 COMMENT \'comment 1\', second_column UInt8 MATERIALIZED first_column COMMENT \'comment 2\', third_column UInt8 ALIAS second_column COMMENT \'comment 3\', fourth_column UInt8 COMMENT \'comment 4\', fifth_column UInt8) ENGINE = TinyLog CREATE TABLE test.check_query_comment_column (`first_column` UInt8 DEFAULT 1 COMMENT \'comment 1\', `second_column` UInt8 MATERIALIZED first_column COMMENT \'comment 2\', `third_column` UInt8 ALIAS second_column COMMENT \'comment 3\', `fourth_column` UInt8 COMMENT \'comment 4\', `fifth_column` UInt8) ENGINE = TinyLog
first_column UInt8 DEFAULT 1 comment 1 first_column UInt8 DEFAULT 1 comment 1
second_column UInt8 MATERIALIZED first_column comment 2 second_column UInt8 MATERIALIZED first_column comment 2
third_column UInt8 ALIAS second_column comment 3 third_column UInt8 ALIAS second_column comment 3
@ -11,7 +11,7 @@ fifth_column UInt8
│ check_query_comment_column │ fourth_column │ comment 4 │ │ check_query_comment_column │ fourth_column │ comment 4 │
│ check_query_comment_column │ fifth_column │ │ │ check_query_comment_column │ fifth_column │ │
└────────────────────────────┴───────────────┴───────────┘ └────────────────────────────┴───────────────┴───────────┘
CREATE TABLE test.check_query_comment_column ( first_column UInt8 DEFAULT 1 COMMENT \'comment 1_1\', second_column UInt8 MATERIALIZED first_column COMMENT \'comment 2_1\', third_column UInt8 ALIAS second_column COMMENT \'comment 3_1\', fourth_column UInt8 COMMENT \'comment 4_1\', fifth_column UInt8 COMMENT \'comment 5_1\') ENGINE = TinyLog CREATE TABLE test.check_query_comment_column (`first_column` UInt8 DEFAULT 1 COMMENT \'comment 1_1\', `second_column` UInt8 MATERIALIZED first_column COMMENT \'comment 2_1\', `third_column` UInt8 ALIAS second_column COMMENT \'comment 3_1\', `fourth_column` UInt8 COMMENT \'comment 4_1\', `fifth_column` UInt8 COMMENT \'comment 5_1\') ENGINE = TinyLog
┌─table──────────────────────┬─name──────────┬─comment─────┐ ┌─table──────────────────────┬─name──────────┬─comment─────┐
│ check_query_comment_column │ first_column │ comment 1_2 │ │ check_query_comment_column │ first_column │ comment 1_2 │
│ check_query_comment_column │ second_column │ comment 2_2 │ │ check_query_comment_column │ second_column │ comment 2_2 │
@ -19,8 +19,8 @@ CREATE TABLE test.check_query_comment_column ( first_column UInt8 DEFAULT 1 COMM
│ check_query_comment_column │ fourth_column │ comment 4_2 │ │ check_query_comment_column │ fourth_column │ comment 4_2 │
│ check_query_comment_column │ fifth_column │ comment 5_2 │ │ check_query_comment_column │ fifth_column │ comment 5_2 │
└────────────────────────────┴───────────────┴─────────────┘ └────────────────────────────┴───────────────┴─────────────┘
CREATE TABLE test.check_query_comment_column ( first_column UInt8 DEFAULT 1 COMMENT \'comment 1_2\', second_column UInt8 MATERIALIZED first_column COMMENT \'comment 2_2\', third_column UInt8 ALIAS second_column COMMENT \'comment 3_2\', fourth_column UInt8 COMMENT \'comment 4_2\', fifth_column UInt8 COMMENT \'comment 5_2\') ENGINE = TinyLog CREATE TABLE test.check_query_comment_column (`first_column` UInt8 DEFAULT 1 COMMENT \'comment 1_2\', `second_column` UInt8 MATERIALIZED first_column COMMENT \'comment 2_2\', `third_column` UInt8 ALIAS second_column COMMENT \'comment 3_2\', `fourth_column` UInt8 COMMENT \'comment 4_2\', `fifth_column` UInt8 COMMENT \'comment 5_2\') ENGINE = TinyLog
CREATE TABLE test.check_query_comment_column ( first_column UInt8 COMMENT \'comment 1\', second_column UInt8 COMMENT \'comment 2\', third_column UInt8 COMMENT \'comment 3\') ENGINE = MergeTree() PARTITION BY second_column ORDER BY first_column SAMPLE BY first_column SETTINGS index_granularity = 8192 CREATE TABLE test.check_query_comment_column (`first_column` UInt8 COMMENT \'comment 1\', `second_column` UInt8 COMMENT \'comment 2\', `third_column` UInt8 COMMENT \'comment 3\') ENGINE = MergeTree() PARTITION BY second_column ORDER BY first_column SAMPLE BY first_column SETTINGS index_granularity = 8192
first_column UInt8 comment 1 first_column UInt8 comment 1
second_column UInt8 comment 2 second_column UInt8 comment 2
third_column UInt8 comment 3 third_column UInt8 comment 3
@ -29,8 +29,8 @@ third_column UInt8 comment 3
│ check_query_comment_column │ second_column │ comment 2 │ │ check_query_comment_column │ second_column │ comment 2 │
│ check_query_comment_column │ third_column │ comment 3 │ │ check_query_comment_column │ third_column │ comment 3 │
└────────────────────────────┴───────────────┴───────────┘ └────────────────────────────┴───────────────┴───────────┘
CREATE TABLE test.check_query_comment_column ( first_column UInt8 COMMENT \'comment 1_2\', second_column UInt8 COMMENT \'comment 2_2\', third_column UInt8 COMMENT \'comment 3_2\') ENGINE = MergeTree() PARTITION BY second_column ORDER BY first_column SAMPLE BY first_column SETTINGS index_granularity = 8192 CREATE TABLE test.check_query_comment_column (`first_column` UInt8 COMMENT \'comment 1_2\', `second_column` UInt8 COMMENT \'comment 2_2\', `third_column` UInt8 COMMENT \'comment 3_2\') ENGINE = MergeTree() PARTITION BY second_column ORDER BY first_column SAMPLE BY first_column SETTINGS index_granularity = 8192
CREATE TABLE test.check_query_comment_column ( first_column UInt8 COMMENT \'comment 1_3\', second_column UInt8 COMMENT \'comment 2_3\', third_column UInt8 COMMENT \'comment 3_3\') ENGINE = MergeTree() PARTITION BY second_column ORDER BY first_column SAMPLE BY first_column SETTINGS index_granularity = 8192 CREATE TABLE test.check_query_comment_column (`first_column` UInt8 COMMENT \'comment 1_3\', `second_column` UInt8 COMMENT \'comment 2_3\', `third_column` UInt8 COMMENT \'comment 3_3\') ENGINE = MergeTree() PARTITION BY second_column ORDER BY first_column SAMPLE BY first_column SETTINGS index_granularity = 8192
┌─table──────────────────────┬─name──────────┬─comment─────┐ ┌─table──────────────────────┬─name──────────┬─comment─────┐
│ check_query_comment_column │ first_column │ comment 1_3 │ │ check_query_comment_column │ first_column │ comment 1_3 │
│ check_query_comment_column │ second_column │ comment 2_3 │ │ check_query_comment_column │ second_column │ comment 2_3 │

View File

@ -1,4 +1,4 @@
CREATE TABLE test.ipv4_test ( ipv4_ IPv4) ENGINE = Memory CREATE TABLE test.ipv4_test (`ipv4_` IPv4) ENGINE = Memory
0.0.0.0 00 0.0.0.0 00
8.8.8.8 08080808 8.8.8.8 08080808
127.0.0.1 7F000001 127.0.0.1 7F000001
@ -10,7 +10,7 @@ CREATE TABLE test.ipv4_test ( ipv4_ IPv4) ENGINE = Memory
> 127.0.0.1 255.255.255.255 > 127.0.0.1 255.255.255.255
= 127.0.0.1 127.0.0.1 = 127.0.0.1 127.0.0.1
euqality of IPv4-mapped IPv6 value and IPv4 promoted to IPv6 with function: 1 euqality of IPv4-mapped IPv6 value and IPv4 promoted to IPv6 with function: 1
CREATE TABLE test.ipv6_test ( ipv6_ IPv6) ENGINE = Memory CREATE TABLE test.ipv6_test (`ipv6_` IPv6) ENGINE = Memory
:: 00000000000000000000000000000000 :: 00000000000000000000000000000000
:: 00000000000000000000000000000000 :: 00000000000000000000000000000000
::ffff:8.8.8.8 00000000000000000000FFFF08080808 ::ffff:8.8.8.8 00000000000000000000FFFF08080808

View File

@ -1,4 +1,4 @@
CREATE MATERIALIZED VIEW test.t_mv ( date Date, platform Enum8('a' = 0, 'b' = 1), app Enum8('a' = 0, 'b' = 1)) ENGINE = MergeTree ORDER BY date SETTINGS index_granularity = 8192 AS SELECT date, platform, app FROM test.t WHERE (app = (SELECT min(app) FROM test.u )) AND (platform = (SELECT (SELECT min(platform) FROM test.v ))) CREATE MATERIALIZED VIEW test.t_mv (`date` Date, `platform` Enum8('a' = 0, 'b' = 1), `app` Enum8('a' = 0, 'b' = 1)) ENGINE = MergeTree ORDER BY date SETTINGS index_granularity = 8192 AS SELECT date, platform, app FROM test.t WHERE (app = (SELECT min(app) FROM test.u )) AND (platform = (SELECT (SELECT min(platform) FROM test.v )))
2000-01-01 a a 2000-01-01 a a
2000-01-02 b b 2000-01-02 b b
2000-01-03 a a 2000-01-03 a a

View File

@ -1,6 +1,6 @@
CREATE TABLE test.check_comments ( column_name1 UInt8 DEFAULT 1 COMMENT \'comment\', column_name2 UInt8 COMMENT \'non default comment\') ENGINE = ReplicatedMergeTree(\'clickhouse/tables/test_comments\', \'r1\') ORDER BY column_name1 SETTINGS index_granularity = 8192 CREATE TABLE test.check_comments (`column_name1` UInt8 DEFAULT 1 COMMENT \'comment\', `column_name2` UInt8 COMMENT \'non default comment\') ENGINE = ReplicatedMergeTree(\'clickhouse/tables/test_comments\', \'r1\') ORDER BY column_name1 SETTINGS index_granularity = 8192
column_name1 UInt8 DEFAULT 1 comment column_name1 UInt8 DEFAULT 1 comment
column_name2 UInt8 non default comment column_name2 UInt8 non default comment
CREATE TABLE test.check_comments ( column_name1 UInt8 DEFAULT 1 COMMENT \'another comment\', column_name2 UInt8 COMMENT \'non default comment\') ENGINE = ReplicatedMergeTree(\'clickhouse/tables/test_comments\', \'r1\') ORDER BY column_name1 SETTINGS index_granularity = 8192 CREATE TABLE test.check_comments (`column_name1` UInt8 DEFAULT 1 COMMENT \'another comment\', `column_name2` UInt8 COMMENT \'non default comment\') ENGINE = ReplicatedMergeTree(\'clickhouse/tables/test_comments\', \'r1\') ORDER BY column_name1 SETTINGS index_granularity = 8192
column_name1 UInt8 DEFAULT 1 another comment column_name1 UInt8 DEFAULT 1 another comment
column_name2 UInt8 non default comment column_name2 UInt8 non default comment

View File

@ -9,4 +9,4 @@
1 2 1 30 1 2 1 30
1 2 4 90 1 2 4 90
*** Check SHOW CREATE TABLE *** *** Check SHOW CREATE TABLE ***
CREATE TABLE test.summing ( x UInt32, y UInt32, z UInt32, val UInt32) ENGINE = SummingMergeTree PRIMARY KEY (x, y) ORDER BY (x, y, -z) SETTINGS index_granularity = 8192 CREATE TABLE test.summing (`x` UInt32, `y` UInt32, `z` UInt32, `val` UInt32) ENGINE = SummingMergeTree PRIMARY KEY (x, y) ORDER BY (x, y, -z) SETTINGS index_granularity = 8192

View File

@ -9,6 +9,6 @@
1 2 1 30 1 2 1 30
1 2 4 90 1 2 4 90
*** Check SHOW CREATE TABLE *** *** Check SHOW CREATE TABLE ***
CREATE TABLE test.summing_r2 ( x UInt32, y UInt32, z UInt32, val UInt32) ENGINE = ReplicatedSummingMergeTree(\'/clickhouse/tables/test/summing\', \'r2\') PRIMARY KEY (x, y) ORDER BY (x, y, -z) SETTINGS index_granularity = 8192 CREATE TABLE test.summing_r2 (`x` UInt32, `y` UInt32, `z` UInt32, `val` UInt32) ENGINE = ReplicatedSummingMergeTree(\'/clickhouse/tables/test/summing\', \'r2\') PRIMARY KEY (x, y) ORDER BY (x, y, -z) SETTINGS index_granularity = 8192
*** Check SHOW CREATE TABLE after offline ALTER *** *** Check SHOW CREATE TABLE after offline ALTER ***
CREATE TABLE test.summing_r2 ( x UInt32, y UInt32, z UInt32, t UInt32, val UInt32) ENGINE = ReplicatedSummingMergeTree(\'/clickhouse/tables/test/summing\', \'r2\') PRIMARY KEY (x, y) ORDER BY (x, y, t * t) SETTINGS index_granularity = 8192 CREATE TABLE test.summing_r2 (`x` UInt32, `y` UInt32, `z` UInt32, `t` UInt32, `val` UInt32) ENGINE = ReplicatedSummingMergeTree(\'/clickhouse/tables/test/summing\', \'r2\') PRIMARY KEY (x, y) ORDER BY (x, y, t * t) SETTINGS index_granularity = 8192

View File

@ -9,10 +9,10 @@
10003 10003
274972506.6 274972506.6
9175437371954010821 9175437371954010821
CREATE TABLE test.compression_codec_multiple_more_types ( id Decimal(38, 13) CODEC(ZSTD(1), LZ4, ZSTD(1), ZSTD(1), Delta(2), Delta(4), Delta(1), LZ4HC(0)), data FixedString(12) CODEC(ZSTD(1), ZSTD(1), Delta(1), Delta(1), Delta(1), NONE, NONE, NONE, LZ4HC(0)), `ddd.age` Array(UInt8) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8)), `ddd.Name` Array(String) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8))) ENGINE = MergeTree() ORDER BY tuple() SETTINGS index_granularity = 8192 CREATE TABLE test.compression_codec_multiple_more_types (`id` Decimal(38, 13) CODEC(ZSTD(1), LZ4, ZSTD(1), ZSTD(1), Delta(2), Delta(4), Delta(1), LZ4HC(0)), `data` FixedString(12) CODEC(ZSTD(1), ZSTD(1), Delta(1), Delta(1), Delta(1), NONE, NONE, NONE, LZ4HC(0)), `ddd.age` Array(UInt8) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8)), `ddd.Name` Array(String) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8))) ENGINE = MergeTree() ORDER BY tuple() SETTINGS index_granularity = 8192
1.5555555555555 hello world! [77] ['John'] 1.5555555555555 hello world! [77] ['John']
7.1000000000000 xxxxxxxxxxxx [127] ['Henry'] 7.1000000000000 xxxxxxxxxxxx [127] ['Henry']
! !
222 222
!ZSTD !ZSTD
CREATE TABLE test.test_default_delta ( id UInt64 CODEC(Delta(8)), data String CODEC(Delta(1)), somedate Date CODEC(Delta(2)), somenum Float64 CODEC(Delta(8)), somestr FixedString(3) CODEC(Delta(1)), othernum Int64 CODEC(Delta(8)), yetothernum Float32 CODEC(Delta(4)), `ddd.age` Array(UInt8) CODEC(Delta(1)), `ddd.Name` Array(String) CODEC(Delta(1)), `ddd.OName` Array(String) CODEC(Delta(1)), `ddd.BName` Array(String) CODEC(Delta(1))) ENGINE = MergeTree() ORDER BY tuple() SETTINGS index_granularity = 8192 CREATE TABLE test.test_default_delta (`id` UInt64 CODEC(Delta(8)), `data` String CODEC(Delta(1)), `somedate` Date CODEC(Delta(2)), `somenum` Float64 CODEC(Delta(8)), `somestr` FixedString(3) CODEC(Delta(1)), `othernum` Int64 CODEC(Delta(8)), `yetothernum` Float32 CODEC(Delta(4)), `ddd.age` Array(UInt8) CODEC(Delta(1)), `ddd.Name` Array(String) CODEC(Delta(1)), `ddd.OName` Array(String) CODEC(Delta(1)), `ddd.BName` Array(String) CODEC(Delta(1))) ENGINE = MergeTree() ORDER BY tuple() SETTINGS index_granularity = 8192

View File

@ -1,9 +1,9 @@
CREATE TABLE test.compression_codec_log ( id UInt64 CODEC(LZ4), data String CODEC(ZSTD(1)), ddd Date CODEC(NONE), somenum Float64 CODEC(ZSTD(2)), somestr FixedString(3) CODEC(LZ4HC(7)), othernum Int64 CODEC(Delta(8))) ENGINE = Log() CREATE TABLE test.compression_codec_log (`id` UInt64 CODEC(LZ4), `data` String CODEC(ZSTD(1)), `ddd` Date CODEC(NONE), `somenum` Float64 CODEC(ZSTD(2)), `somestr` FixedString(3) CODEC(LZ4HC(7)), `othernum` Int64 CODEC(Delta(8))) ENGINE = Log()
1 hello 2018-12-14 1.1 aaa 5 1 hello 2018-12-14 1.1 aaa 5
2 world 2018-12-15 2.2 bbb 6 2 world 2018-12-15 2.2 bbb 6
3 ! 2018-12-16 3.3 ccc 7 3 ! 2018-12-16 3.3 ccc 7
2 2
CREATE TABLE test.compression_codec_multiple_log ( id UInt64 CODEC(LZ4, ZSTD(1), NONE, LZ4HC(0), Delta(4)), data String CODEC(ZSTD(2), NONE, Delta(2), LZ4HC(0), LZ4, LZ4, Delta(8)), ddd Date CODEC(NONE, NONE, NONE, Delta(1), LZ4, ZSTD(1), LZ4HC(0), LZ4HC(0)), somenum Float64 CODEC(Delta(4), LZ4, LZ4, ZSTD(2), LZ4HC(5), ZSTD(3), ZSTD(1))) ENGINE = Log() CREATE TABLE test.compression_codec_multiple_log (`id` UInt64 CODEC(LZ4, ZSTD(1), NONE, LZ4HC(0), Delta(4)), `data` String CODEC(ZSTD(2), NONE, Delta(2), LZ4HC(0), LZ4, LZ4, Delta(8)), `ddd` Date CODEC(NONE, NONE, NONE, Delta(1), LZ4, ZSTD(1), LZ4HC(0), LZ4HC(0)), `somenum` Float64 CODEC(Delta(4), LZ4, LZ4, ZSTD(2), LZ4HC(5), ZSTD(3), ZSTD(1))) ENGINE = Log()
1 world 2018-10-05 1.1 1 world 2018-10-05 1.1
2 hello 2018-10-01 2.2 2 hello 2018-10-01 2.2
3 buy 2018-10-11 3.3 3 buy 2018-10-11 3.3
@ -11,12 +11,12 @@ CREATE TABLE test.compression_codec_multiple_log ( id UInt64 CODEC(LZ4, ZSTD(1),
10003 10003
274972506.6 274972506.6
9175437371954010821 9175437371954010821
CREATE TABLE test.compression_codec_tiny_log ( id UInt64 CODEC(LZ4), data String CODEC(ZSTD(1)), ddd Date CODEC(NONE), somenum Float64 CODEC(ZSTD(2)), somestr FixedString(3) CODEC(LZ4HC(7)), othernum Int64 CODEC(Delta(8))) ENGINE = TinyLog() CREATE TABLE test.compression_codec_tiny_log (`id` UInt64 CODEC(LZ4), `data` String CODEC(ZSTD(1)), `ddd` Date CODEC(NONE), `somenum` Float64 CODEC(ZSTD(2)), `somestr` FixedString(3) CODEC(LZ4HC(7)), `othernum` Int64 CODEC(Delta(8))) ENGINE = TinyLog()
1 hello 2018-12-14 1.1 aaa 5 1 hello 2018-12-14 1.1 aaa 5
2 world 2018-12-15 2.2 bbb 6 2 world 2018-12-15 2.2 bbb 6
3 ! 2018-12-16 3.3 ccc 7 3 ! 2018-12-16 3.3 ccc 7
2 2
CREATE TABLE test.compression_codec_multiple_tiny_log ( id UInt64 CODEC(LZ4, ZSTD(1), NONE, LZ4HC(0), Delta(4)), data String CODEC(ZSTD(2), NONE, Delta(2), LZ4HC(0), LZ4, LZ4, Delta(8)), ddd Date CODEC(NONE, NONE, NONE, Delta(1), LZ4, ZSTD(1), LZ4HC(0), LZ4HC(0)), somenum Float64 CODEC(Delta(4), LZ4, LZ4, ZSTD(2), LZ4HC(5), ZSTD(3), ZSTD(1))) ENGINE = TinyLog() CREATE TABLE test.compression_codec_multiple_tiny_log (`id` UInt64 CODEC(LZ4, ZSTD(1), NONE, LZ4HC(0), Delta(4)), `data` String CODEC(ZSTD(2), NONE, Delta(2), LZ4HC(0), LZ4, LZ4, Delta(8)), `ddd` Date CODEC(NONE, NONE, NONE, Delta(1), LZ4, ZSTD(1), LZ4HC(0), LZ4HC(0)), `somenum` Float64 CODEC(Delta(4), LZ4, LZ4, ZSTD(2), LZ4HC(5), ZSTD(3), ZSTD(1))) ENGINE = TinyLog()
1 world 2018-10-05 1.1 1 world 2018-10-05 1.1
2 hello 2018-10-01 2.2 2 hello 2018-10-01 2.2
3 buy 2018-10-11 3.3 3 buy 2018-10-11 3.3

View File

@ -17,7 +17,8 @@ ${CLICKHOUSE_CLIENT} --query="SELECT '*** Create and kill a single invalid mutat
${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation DELETE WHERE toUInt32(s) = 1" ${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation DELETE WHERE toUInt32(s) = 1"
sleep 0.1 sleep 0.1
${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_1_1_0', '20010101_2_2_0'), latest_fail_time != 0, substr(latest_fail_reason, 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation'"
${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_1_1_0', '20010101_2_2_0'), latest_fail_time != 0, substr(replaceRegexpOne(latest_fail_reason, '.version [0-9.]+. ', ''), 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation'"
${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation'" ${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation'"
@ -29,7 +30,7 @@ ${CLICKHOUSE_CLIENT} --query="SELECT '*** Create and kill invalid mutation that
${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation DELETE WHERE toUInt32(s) = 1" ${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation DELETE WHERE toUInt32(s) = 1"
${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation DELETE WHERE x = 1" ${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation DELETE WHERE x = 1"
${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_1_1_0', '20010101_2_2_0'), latest_fail_time != 0, substr(latest_fail_reason, 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation' AND mutation_id = 'mutation_4.txt'" ${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_1_1_0', '20010101_2_2_0'), latest_fail_time != 0, substr(replaceRegexpOne(latest_fail_reason, '.version [0-9.]+. ', ''), 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation' AND mutation_id = 'mutation_4.txt'"
sleep 0.1 sleep 0.1
${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation' AND mutation_id = 'mutation_4.txt'" ${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation' AND mutation_id = 'mutation_4.txt'"

View File

@ -20,7 +20,7 @@ ${CLICKHOUSE_CLIENT} --query="SELECT '*** Create and kill a single invalid mutat
${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation_r1 DELETE WHERE toUInt32(s) = 1" ${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation_r1 DELETE WHERE toUInt32(s) = 1"
sleep 1 sleep 1
${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_0_0_0', '20010101_0_0_0'), latest_fail_time != 0, substr(latest_fail_reason, 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation_r1'" ${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_0_0_0', '20010101_0_0_0'), latest_fail_time != 0, substr(replaceRegexpOne(latest_fail_reason, '.version [0-9.]+. ', ''), 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation_r1'"
${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation_r1'" ${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation_r1'"
@ -34,7 +34,7 @@ ${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation_r1 DELETE WHERE toU
${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation_r1 DELETE WHERE x = 1" ${CLICKHOUSE_CLIENT} --query="ALTER TABLE test.kill_mutation_r1 DELETE WHERE x = 1"
sleep 1 sleep 1
${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_0_0_0_1', '20010101_0_0_0_1'), latest_fail_time != 0, substr(latest_fail_reason, 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation_r1' AND mutation_id = '0000000001'" ${CLICKHOUSE_CLIENT} --query="SELECT mutation_id, latest_failed_part IN ('20000101_0_0_0_1', '20010101_0_0_0_1'), latest_fail_time != 0, substr(replaceRegexpOne(latest_fail_reason, '.version [0-9.]+. ', ''), 1, 8) FROM system.mutations WHERE database = 'test' AND table = 'kill_mutation_r1' AND mutation_id = '0000000001'"
${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation_r1' AND mutation_id = '0000000001'" ${CLICKHOUSE_CLIENT} --query="KILL MUTATION WHERE database = 'test' AND table = 'kill_mutation_r1' AND mutation_id = '0000000001'"

View File

@ -1,4 +1,4 @@
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 2 1 2
1 2 1 2
@ -6,15 +6,15 @@ CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYP
1 2 1 2
1 2 1 2
1 2 1 2
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 2 1 2
1 2 1 2
1 2 1 2
1 2 1 2
1 2 1 2
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 2 1 2
1 2 1 2
@ -23,6 +23,6 @@ CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYP
1 2 1 2
1 2 1 2
1 2 1 2
CREATE TABLE test.minmax_idx2 ( u64 UInt64, i32 Int32) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx2 (`u64` UInt64, `i32` Int32) ENGINE = MergeTree() ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 2 1 2

View File

@ -1,5 +1,5 @@
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx_r (`u64` UInt64, `i32` Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 2 1 2
1 2 1 2
@ -14,8 +14,8 @@ CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 T
3 2 3 2
19 9 19 9
65 75 65 75
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx_r (`u64` UInt64, `i32` Int32, INDEX idx3 u64 - i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 + i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 4 1 4
1 5 1 5
@ -28,10 +28,10 @@ CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32, INDEX idx3 u64 - i32 T
3 2 3 2
19 9 19 9
65 75 65 75
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx_r (`u64` UInt64, `i32` Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx (`u64` UInt64, `i32` Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx_r (`u64` UInt64, `i32` Int32, INDEX idx1 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter1\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 4 1 4
1 5 1 5
@ -44,14 +44,14 @@ CREATE TABLE test.minmax_idx_r ( u64 UInt64, i32 Int32, INDEX idx1 u64 * i32 T
3 2 3 2
19 9 19 9
65 75 65 75
CREATE TABLE test.minmax_idx2 ( u64 UInt64, i32 Int32, INDEX idx1 u64 + i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx2 (`u64` UInt64, `i32` Int32, INDEX idx1 u64 + i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx2_r ( u64 UInt64, i32 Int32, INDEX idx1 u64 + i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx2_r (`u64` UInt64, `i32` Int32, INDEX idx1 u64 + i32 TYPE minmax GRANULARITY 10, INDEX idx2 u64 * i32 TYPE minmax GRANULARITY 10) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 3 1 3
1 2 1 2
1 3 1 3
CREATE TABLE test.minmax_idx2 ( u64 UInt64, i32 Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx2 (`u64` UInt64, `i32` Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r1\') ORDER BY u64 SETTINGS index_granularity = 8192
CREATE TABLE test.minmax_idx2_r ( u64 UInt64, i32 Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192 CREATE TABLE test.minmax_idx2_r (`u64` UInt64, `i32` Int32) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/indices_alter2\', \'r2\') ORDER BY u64 SETTINGS index_granularity = 8192
1 2 1 2
1 3 1 3
1 2 1 2

View File

@ -0,0 +1,44 @@
on
l \N \N String Nullable(String)
l \N \N String Nullable(String)
r \N String Nullable(String)
\N r \N Nullable(String) Nullable(String)
l \N String Nullable(String)
l \N String Nullable(String)
r \N String Nullable(String)
\N r \N Nullable(String) Nullable(String)
\N \N
0 \N
using
l \N String Nullable(String)
l \N String Nullable(String)
\N String Nullable(String)
\N \N Nullable(String) Nullable(String)
l \N String Nullable(String)
l \N String Nullable(String)
\N String Nullable(String)
\N \N Nullable(String) Nullable(String)
\N \N
0 \N
on + join_use_nulls
l \N \N TODO Nullable(String)
l \N \N TODO Nullable(String)
r \N TODO Nullable(String)
\N r \N Nullable(String) Nullable(String)
l \N TODO Nullable(String)
l \N TODO Nullable(String)
r \N TODO Nullable(String)
\N r \N Nullable(String) Nullable(String)
\N \N
0 \N
using + join_use_nulls
l \N TODO Nullable(String)
l \N TODO Nullable(String)
\N TODO Nullable(String)
\N \N Nullable(String) Nullable(String)
l \N TODO Nullable(String)
l \N TODO Nullable(String)
\N TODO Nullable(String)
\N \N Nullable(String) Nullable(String)
\N \N
0 \N

View File

@ -0,0 +1,69 @@
USE test;
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t3;
CREATE TABLE t1 ( id String ) ENGINE = Memory;
CREATE TABLE t2 ( id Nullable(String) ) ENGINE = Memory;
CREATE TABLE t3 ( id Nullable(String), not_id Nullable(String) ) ENGINE = Memory;
insert into t1 values ('l');
insert into t3 (id) values ('r');
SELECT 'on';
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 ANY LEFT JOIN t3 ON t1.id = t3.id;
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 ANY FULL JOIN t3 ON t1.id = t3.id;
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 ANY FULL JOIN t3 ON t2.id = t3.id;
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 LEFT JOIN t3 ON t1.id = t3.id;
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 FULL JOIN t3 ON t1.id = t3.id;
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 FULL JOIN t3 ON t2.id = t3.id;
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 ANY LEFT JOIN t3 ON t1.id = t3.id;
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 LEFT JOIN t3 ON t1.id = t3.id;
SELECT 'using';
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 ANY LEFT JOIN t3 USING(id);
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 ANY FULL JOIN t3 USING(id);
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 ANY FULL JOIN t3 USING(id);
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 LEFT JOIN t3 USING(id);
SELECT *, toTypeName(t1.id), toTypeName(t3.id) FROM t1 FULL JOIN t3 USING(id);
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 FULL JOIN t3 USING(id);
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 ANY LEFT JOIN t3 USING(id);
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 LEFT JOIN t3 USING(id);
SET join_use_nulls = 1;
-- TODO: toTypeName(t1.id) String -> Nullable(String)
SELECT 'on + join_use_nulls';
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 ANY LEFT JOIN t3 ON t1.id = t3.id;
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 ANY FULL JOIN t3 ON t1.id = t3.id;
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 ANY FULL JOIN t3 ON t2.id = t3.id;
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 LEFT JOIN t3 ON t1.id = t3.id;
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 FULL JOIN t3 ON t1.id = t3.id;
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 FULL JOIN t3 ON t2.id = t3.id;
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 ANY LEFT JOIN t3 ON t1.id = t3.id;
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 LEFT JOIN t3 ON t1.id = t3.id;
SELECT 'using + join_use_nulls';
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 ANY LEFT JOIN t3 USING(id);
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 ANY FULL JOIN t3 USING(id);
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 ANY FULL JOIN t3 USING(id);
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 LEFT JOIN t3 USING(id);
SELECT *, 'TODO', toTypeName(t3.id) FROM t1 FULL JOIN t3 USING(id);
SELECT *, toTypeName(t2.id), toTypeName(t3.id) FROM t2 FULL JOIN t3 USING(id);
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 ANY LEFT JOIN t3 USING(id);
SELECT t3.id = 'l', t3.not_id = 'l' FROM t1 LEFT JOIN t3 USING(id);
DROP TABLE t1;
DROP TABLE t2;

View File

@ -0,0 +1,2 @@
1 0
\N 1

View File

@ -0,0 +1,19 @@
USE test;
DROP TABLE IF EXISTS table1;
DROP TABLE IF EXISTS table2;
CREATE TABLE table1 ( id String ) ENGINE = Log;
CREATE TABLE table2 ( parent_id String ) ENGINE = Log;
insert into table1 values ('1');
SELECT table2.parent_id = '', isNull(table2.parent_id)
FROM table1 ANY LEFT JOIN table2 ON table1.id = table2.parent_id;
SET join_use_nulls = 1;
SELECT table2.parent_id = '', isNull(table2.parent_id)
FROM table1 ANY LEFT JOIN table2 ON table1.id = table2.parent_id;
DROP TABLE test.table1;
DROP TABLE test.table2;

View File

@ -1,4 +1,3 @@
CREATE DATABASE IF NOT EXISTS test;
DROP TABLE IF EXISTS test.defaults; DROP TABLE IF EXISTS test.defaults;
CREATE TABLE IF NOT EXISTS test.defaults CREATE TABLE IF NOT EXISTS test.defaults
( (
@ -9,7 +8,6 @@ insert into test.defaults values ('ba'), ('aa'), ('ba'), ('b'), ('ba'), ('aa');
select val < 1.5 and val > 1.459 from (select entropy(vals) as val from test.defaults); select val < 1.5 and val > 1.459 from (select entropy(vals) as val from test.defaults);
CREATE DATABASE IF NOT EXISTS test;
DROP TABLE IF EXISTS test.defaults; DROP TABLE IF EXISTS test.defaults;
CREATE TABLE IF NOT EXISTS test.defaults CREATE TABLE IF NOT EXISTS test.defaults
( (
@ -19,7 +17,6 @@ insert into test.defaults values (0), (0), (1), (0), (0), (0), (1), (2), (3), (5
select val < 2.4 and val > 2.3393 from (select entropy(vals) as val from test.defaults); select val < 2.4 and val > 2.3393 from (select entropy(vals) as val from test.defaults);
CREATE DATABASE IF NOT EXISTS test;
DROP TABLE IF EXISTS test.defaults; DROP TABLE IF EXISTS test.defaults;
CREATE TABLE IF NOT EXISTS test.defaults CREATE TABLE IF NOT EXISTS test.defaults
( (
@ -29,7 +26,6 @@ insert into test.defaults values (0), (0), (1), (0), (0), (0), (1), (2), (3), (5
select val < 2.4 and val > 2.3393 from (select entropy(vals) as val from test.defaults); select val < 2.4 and val > 2.3393 from (select entropy(vals) as val from test.defaults);
CREATE DATABASE IF NOT EXISTS test;
DROP TABLE IF EXISTS test.defaults; DROP TABLE IF EXISTS test.defaults;
CREATE TABLE IF NOT EXISTS test.defaults CREATE TABLE IF NOT EXISTS test.defaults
( (
@ -39,7 +35,6 @@ insert into test.defaults values (0), (0), (-1), (0), (0), (0), (-1), (2), (3),
select val < 2.4 and val > 2.3393 from (select entropy(vals) as val from test.defaults); select val < 2.4 and val > 2.3393 from (select entropy(vals) as val from test.defaults);
CREATE DATABASE IF NOT EXISTS test;
DROP TABLE IF EXISTS test.defaults; DROP TABLE IF EXISTS test.defaults;
CREATE TABLE IF NOT EXISTS test.defaults CREATE TABLE IF NOT EXISTS test.defaults
( (

View File

@ -20,7 +20,7 @@
274972506.6 274972506.6
9175437371954010821 9175437371954010821
9175437371954010821 9175437371954010821
CREATE TABLE test.compression_codec_multiple_more_types_replicated ( id Decimal(38, 13) CODEC(ZSTD(1), LZ4, ZSTD(1), ZSTD(1), Delta(2), Delta(4), Delta(1), LZ4HC(0)), data FixedString(12) CODEC(ZSTD(1), ZSTD(1), Delta(1), Delta(1), Delta(1), NONE, NONE, NONE, LZ4HC(0)), `ddd.age` Array(UInt8) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8)), `ddd.Name` Array(String) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8))) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/compression_codec_multiple_more_types_replicated\', \'1\') ORDER BY tuple() SETTINGS index_granularity = 8192 CREATE TABLE test.compression_codec_multiple_more_types_replicated (`id` Decimal(38, 13) CODEC(ZSTD(1), LZ4, ZSTD(1), ZSTD(1), Delta(2), Delta(4), Delta(1), LZ4HC(0)), `data` FixedString(12) CODEC(ZSTD(1), ZSTD(1), Delta(1), Delta(1), Delta(1), NONE, NONE, NONE, LZ4HC(0)), `ddd.age` Array(UInt8) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8)), `ddd.Name` Array(String) CODEC(LZ4, LZ4HC(0), NONE, NONE, NONE, ZSTD(1), Delta(8))) ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/compression_codec_multiple_more_types_replicated\', \'1\') ORDER BY tuple() SETTINGS index_granularity = 8192
1.5555555555555 hello world! [77] ['John'] 1.5555555555555 hello world! [77] ['John']
7.1000000000000 xxxxxxxxxxxx [127] ['Henry'] 7.1000000000000 xxxxxxxxxxxx [127] ['Henry']
! !

View File

@ -1,6 +1,7 @@
SET send_logs_level = 'none'; SET send_logs_level = 'none';
DROP TABLE IF EXISTS test.compression_codec_replicated; DROP TABLE IF EXISTS test.compression_codec_replicated1;
DROP TABLE IF EXISTS test.compression_codec_replicated2;
CREATE TABLE test.compression_codec_replicated1( CREATE TABLE test.compression_codec_replicated1(
id UInt64 CODEC(LZ4), id UInt64 CODEC(LZ4),

View File

@ -1,2 +1,2 @@
CREATE VIEW test.t ( number UInt64) AS SELECT number FROM system.numbers CREATE VIEW test.t (`number` UInt64) AS SELECT number FROM system.numbers
CREATE VIEW test.t ( next_number UInt64) AS SELECT number + 1 AS next_number FROM system.numbers CREATE VIEW test.t (`next_number` UInt64) AS SELECT number + 1 AS next_number FROM system.numbers

View File

@ -0,0 +1,29 @@
1 1970-01-01 00:00:01 1 0 0000-00-00 00:00:00 0
1 1970-01-01 00:00:02 2 2 1970-01-01 00:00:02 1
1 1970-01-01 00:00:03 3 2 1970-01-01 00:00:03 1
1 1970-01-01 00:00:04 4 4 1970-01-01 00:00:04 1
1 1970-01-01 00:00:05 5 4 1970-01-01 00:00:05 1
2 1970-01-01 00:00:01 1 0 0000-00-00 00:00:00 0
2 1970-01-01 00:00:02 2 0 0000-00-00 00:00:00 0
2 1970-01-01 00:00:03 3 3 1970-01-01 00:00:03 2
2 1970-01-01 00:00:04 4 3 1970-01-01 00:00:04 2
2 1970-01-01 00:00:05 5 3 1970-01-01 00:00:05 2
3 1970-01-01 00:00:01 1 0 0000-00-00 00:00:00 0
3 1970-01-01 00:00:02 2 0 0000-00-00 00:00:00 0
3 1970-01-01 00:00:03 3 0 0000-00-00 00:00:00 0
3 1970-01-01 00:00:04 4 0 0000-00-00 00:00:00 0
3 1970-01-01 00:00:05 5 0 0000-00-00 00:00:00 0
1 1970-01-01 00:00:02 2 2 1970-01-01 00:00:02 1
1 1970-01-01 00:00:03 3 2 1970-01-01 00:00:03 1
1 1970-01-01 00:00:04 4 4 1970-01-01 00:00:04 1
1 1970-01-01 00:00:05 5 4 1970-01-01 00:00:05 1
2 1970-01-01 00:00:03 3 3 1970-01-01 00:00:03 2
2 1970-01-01 00:00:04 4 3 1970-01-01 00:00:04 2
2 1970-01-01 00:00:05 5 3 1970-01-01 00:00:05 2
1 1970-01-01 00:00:02 2 2 1970-01-01 00:00:02 1
1 1970-01-01 00:00:03 3 2 1970-01-01 00:00:03 1
1 1970-01-01 00:00:04 4 4 1970-01-01 00:00:04 1
1 1970-01-01 00:00:05 5 4 1970-01-01 00:00:05 1
2 1970-01-01 00:00:03 3 3 1970-01-01 00:00:03 2
2 1970-01-01 00:00:04 4 3 1970-01-01 00:00:04 2
2 1970-01-01 00:00:05 5 3 1970-01-01 00:00:05 2

View File

@ -0,0 +1,22 @@
USE test;
DROP TABLE IF EXISTS A;
DROP TABLE IF EXISTS B;
CREATE TABLE A(k UInt32, t DateTime, a Float64) ENGINE = MergeTree() ORDER BY (k, t);
INSERT INTO A(k,t,a) VALUES (1,1,1),(1,2,2),(1,3,3),(1,4,4),(1,5,5); -- multiple joined values
INSERT INTO A(k,t,a) VALUES (2,1,1),(2,2,2),(2,3,3),(2,4,4),(2,5,5); -- one joined value
INSERT INTO A(k,t,a) VALUES (3,1,1),(3,2,2),(3,3,3),(3,4,4),(3,5,5); -- no joined values
CREATE TABLE B(k UInt32, t DateTime, b Float64) ENGINE = MergeTree() ORDER BY (k, t);
INSERT INTO B(k,t,b) VALUES (1,2,2),(1,4,4);
INSERT INTO B(k,t,b) VALUES (2,3,3);
SELECT A.k, toString(A.t, 'UTC'), A.a, B.b, toString(B.t, 'UTC'), B.k FROM A ASOF LEFT JOIN B USING(k,t) ORDER BY (A.k, A.t);
SELECT A.k, toString(A.t, 'UTC'), A.a, B.b, toString(B.t, 'UTC'), B.k FROM A ASOF INNER JOIN B ON A.k == B.k AND A.t == B.t ORDER BY (A.k, A.t);
SELECT A.k, toString(A.t, 'UTC'), A.a, B.b, toString(B.t, 'UTC'), B.k FROM A ASOF JOIN B USING(k,t) ORDER BY (A.k, A.t);
DROP TABLE A;
DROP TABLE B;

View File

@ -0,0 +1,14 @@
1 1970-01-01 00:00:05 1 1.5 2
1 1970-01-01 00:00:06 1 1.51 2
1 1970-01-01 00:00:10 11 11.5 12
1 1970-01-01 00:00:11 11 11.51 12
1 1970-01-01 00:00:15 5 5.5 6
1 1970-01-01 00:00:16 5 5.6 6
1 1970-01-01 00:00:20 7 7.5 8
2 1970-01-01 00:00:05 11 2.5 12
2 1970-01-01 00:00:06 11 2.51 12
2 1970-01-01 00:00:10 21 12.5 22
2 1970-01-01 00:00:11 21 12.51 22
2 1970-01-01 00:00:15 5 6.5 6
2 1970-01-01 00:00:16 5 5.6 6
2 1970-01-01 00:00:20 17 8.5 18

View File

@ -0,0 +1,17 @@
USE test;
DROP TABLE IF EXISTS md;
DROP TABLE IF EXISTS tv;
CREATE TABLE md(key UInt32, t DateTime, bid Float64, ask Float64) ENGINE = MergeTree() ORDER BY (key, t);
INSERT INTO test.md(key,t,bid,ask) VALUES (1,20,7,8),(1,5,1,2),(1,10,11,12),(1,15,5,6);
INSERT INTO test.md(key,t,bid,ask) VALUES (2,20,17,18),(2,5,11,12),(2,10,21,22),(2,15,5,6);
CREATE TABLE tv(key UInt32, t DateTime, tv Float64) ENGINE = MergeTree() ORDER BY (key, t);
INSERT INTO test.tv(key,t,tv) VALUES (1,5,1.5),(1,6,1.51),(1,10,11.5),(1,11,11.51),(1,15,5.5),(1,16,5.6),(1,20,7.5);
INSERT INTO test.tv(key,t,tv) VALUES (2,5,2.5),(2,6,2.51),(2,10,12.5),(2,11,12.51),(2,15,6.5),(2,16,5.6),(2,20,8.5);
SELECT tv.key, toString(tv.t, 'UTC'), md.bid, tv.tv, md.ask FROM tv ASOF LEFT JOIN md USING(key,t) ORDER BY (tv.key, tv.t);
DROP TABLE md;
DROP TABLE tv;

View File

@ -0,0 +1,9 @@
1
1
1
1
0
1
1
1
0

View File

@ -0,0 +1,6 @@
SET allow_hyperscan = 1;
SELECT multiMatchAny(arrayJoin(['hello', 'world', 'hellllllllo', 'wororld', 'abc']), ['hel+o', 'w(or)*ld']);
SET allow_hyperscan = 0;
SELECT multiMatchAny(arrayJoin(['hello', 'world', 'hellllllllo', 'wororld', 'abc']), ['hel+o', 'w(or)*ld']); -- { serverError 446 }
SELECT multiSearchAny(arrayJoin(['hello', 'world', 'hello, world', 'abc']), ['hello', 'world']);

View File

@ -0,0 +1,3 @@
1
2
[1,8]

View File

@ -0,0 +1,3 @@
SELECT multiMatchAny('goodbye', ['^hello[, ]+world$', 'go+d *bye', 'w(or)+ld']);
SELECT multiMatchAnyIndex('goodbye', ['^hello[, ]+world$', 'go+d *bye', 'w(or)+ld']);
SELECT multiSearchAllPositions('hello, world', ['hello', 'world']);

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