Merge branch 'master' of https://github.com/ClickHouse/ClickHouse into hdfs-idisk

This commit is contained in:
kssenii 2021-04-17 17:27:14 +00:00
commit 82b1f1304f
413 changed files with 6899 additions and 2202 deletions

3
.gitmodules vendored
View File

@ -221,6 +221,9 @@
[submodule "contrib/NuRaft"] [submodule "contrib/NuRaft"]
path = contrib/NuRaft path = contrib/NuRaft
url = https://github.com/ClickHouse-Extras/NuRaft.git url = https://github.com/ClickHouse-Extras/NuRaft.git
[submodule "contrib/nanodbc"]
path = contrib/nanodbc
url = https://github.com/ClickHouse-Extras/nanodbc.git
[submodule "contrib/datasketches-cpp"] [submodule "contrib/datasketches-cpp"]
path = contrib/datasketches-cpp path = contrib/datasketches-cpp
url = https://github.com/ClickHouse-Extras/datasketches-cpp.git url = https://github.com/ClickHouse-Extras/datasketches-cpp.git

View File

@ -11,10 +11,13 @@
* Now replicas that are processing the `ALTER TABLE ATTACH PART[ITION]` command search in their `detached/` folders before fetching the data from other replicas. As an implementation detail, a new command `ATTACH_PART` is introduced in the replicated log. Parts are searched and compared by their checksums. [#18978](https://github.com/ClickHouse/ClickHouse/pull/18978) ([Mike Kot](https://github.com/myrrc)). **Note**: * Now replicas that are processing the `ALTER TABLE ATTACH PART[ITION]` command search in their `detached/` folders before fetching the data from other replicas. As an implementation detail, a new command `ATTACH_PART` is introduced in the replicated log. Parts are searched and compared by their checksums. [#18978](https://github.com/ClickHouse/ClickHouse/pull/18978) ([Mike Kot](https://github.com/myrrc)). **Note**:
* `ATTACH PART[ITION]` queries may not work during cluster upgrade. * `ATTACH PART[ITION]` queries may not work during cluster upgrade.
* It's not possible to rollback to older ClickHouse version after executing `ALTER ... ATTACH` query in new version as the old servers would fail to pass the `ATTACH_PART` entry in the replicated log. * It's not possible to rollback to older ClickHouse version after executing `ALTER ... ATTACH` query in new version as the old servers would fail to pass the `ATTACH_PART` entry in the replicated log.
* In this version, empty `<remote_url_allow_hosts></remote_url_allow_hosts>` will block all access to remote hosts while in previous versions it did nothing. If you want to keep old behaviour and you have empty `remote_url_allow_hosts` element in configuration file, remove it. [#20058](https://github.com/ClickHouse/ClickHouse/pull/20058) ([Vladimir Chebotarev](https://github.com/excitoon)).
#### New Feature #### New Feature
* Extended range of `DateTime64` to support dates from year 1925 to 2283. Improved support of `DateTime` around zero date (`1970-01-01`). [#9404](https://github.com/ClickHouse/ClickHouse/pull/9404) ([alexey-milovidov](https://github.com/alexey-milovidov), [Vasily Nemkov](https://github.com/Enmk)). * Extended range of `DateTime64` to support dates from year 1925 to 2283. Improved support of `DateTime` around zero date (`1970-01-01`). [#9404](https://github.com/ClickHouse/ClickHouse/pull/9404) ([alexey-milovidov](https://github.com/alexey-milovidov), [Vasily Nemkov](https://github.com/Enmk)). Not every time and date functions are working for extended range of dates.
* Added support of Kerberos authentication for preconfigured users and HTTP requests (GSS-SPNEGO). [#14995](https://github.com/ClickHouse/ClickHouse/pull/14995) ([Denis Glazachev](https://github.com/traceon)).
* Add `prefer_column_name_to_alias` setting to use original column names instead of aliases. it is needed to be more compatible with common databases' aliasing rules. This is for [#9715](https://github.com/ClickHouse/ClickHouse/issues/9715) and [#9887](https://github.com/ClickHouse/ClickHouse/issues/9887). [#22044](https://github.com/ClickHouse/ClickHouse/pull/22044) ([Amos Bird](https://github.com/amosbird)). * Add `prefer_column_name_to_alias` setting to use original column names instead of aliases. it is needed to be more compatible with common databases' aliasing rules. This is for [#9715](https://github.com/ClickHouse/ClickHouse/issues/9715) and [#9887](https://github.com/ClickHouse/ClickHouse/issues/9887). [#22044](https://github.com/ClickHouse/ClickHouse/pull/22044) ([Amos Bird](https://github.com/amosbird)).
* Added functions `dictGetChildren(dictionary, key)`, `dictGetDescendants(dictionary, key, level)`. Function `dictGetChildren` return all children as an array if indexes. It is a inverse transformation for `dictGetHierarchy`. Function `dictGetDescendants` return all descendants as if `dictGetChildren` was applied `level` times recursively. Zero `level` value is equivalent to infinity. Closes [#14656](https://github.com/ClickHouse/ClickHouse/issues/14656). [#22096](https://github.com/ClickHouse/ClickHouse/pull/22096) ([Maksim Kita](https://github.com/kitaisreal)). * Added functions `dictGetChildren(dictionary, key)`, `dictGetDescendants(dictionary, key, level)`. Function `dictGetChildren` return all children as an array if indexes. It is a inverse transformation for `dictGetHierarchy`. Function `dictGetDescendants` return all descendants as if `dictGetChildren` was applied `level` times recursively. Zero `level` value is equivalent to infinity. Closes [#14656](https://github.com/ClickHouse/ClickHouse/issues/14656). [#22096](https://github.com/ClickHouse/ClickHouse/pull/22096) ([Maksim Kita](https://github.com/kitaisreal)).
* Added `executable_pool` dictionary source. Close [#14528](https://github.com/ClickHouse/ClickHouse/issues/14528). [#21321](https://github.com/ClickHouse/ClickHouse/pull/21321) ([Maksim Kita](https://github.com/kitaisreal)). * Added `executable_pool` dictionary source. Close [#14528](https://github.com/ClickHouse/ClickHouse/issues/14528). [#21321](https://github.com/ClickHouse/ClickHouse/pull/21321) ([Maksim Kita](https://github.com/kitaisreal)).
@ -131,7 +134,6 @@
* Fix receive and send timeouts and non-blocking read in secure socket. [#21429](https://github.com/ClickHouse/ClickHouse/pull/21429) ([Kruglov Pavel](https://github.com/Avogar)). * Fix receive and send timeouts and non-blocking read in secure socket. [#21429](https://github.com/ClickHouse/ClickHouse/pull/21429) ([Kruglov Pavel](https://github.com/Avogar)).
* `force_drop_table` flag didn't work for `MATERIALIZED VIEW`, it's fixed. Fixes [#18943](https://github.com/ClickHouse/ClickHouse/issues/18943). [#20626](https://github.com/ClickHouse/ClickHouse/pull/20626) ([tavplubix](https://github.com/tavplubix)). * `force_drop_table` flag didn't work for `MATERIALIZED VIEW`, it's fixed. Fixes [#18943](https://github.com/ClickHouse/ClickHouse/issues/18943). [#20626](https://github.com/ClickHouse/ClickHouse/pull/20626) ([tavplubix](https://github.com/tavplubix)).
* Fix name clashes in `PredicateRewriteVisitor`. It caused incorrect `WHERE` filtration after full join. Close [#20497](https://github.com/ClickHouse/ClickHouse/issues/20497). [#20622](https://github.com/ClickHouse/ClickHouse/pull/20622) ([Vladimir](https://github.com/vdimir)). * Fix name clashes in `PredicateRewriteVisitor`. It caused incorrect `WHERE` filtration after full join. Close [#20497](https://github.com/ClickHouse/ClickHouse/issues/20497). [#20622](https://github.com/ClickHouse/ClickHouse/pull/20622) ([Vladimir](https://github.com/vdimir)).
* Fixed open behavior of remote host filter in case when there is `remote_url_allow_hosts` section in configuration but no entries there. [#20058](https://github.com/ClickHouse/ClickHouse/pull/20058) ([Vladimir Chebotarev](https://github.com/excitoon)).
#### Build/Testing/Packaging Improvement #### Build/Testing/Packaging Improvement

View File

@ -290,6 +290,12 @@ if (COMPILER_GCC OR COMPILER_CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation")
endif () endif ()
# falign-functions=32 prevents from random performance regressions with the code change. Thus, providing more stable
# benchmarks.
if (COMPILER_GCC OR COMPILER_CLANG)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -falign-functions=32")
endif ()
# Compiler-specific coverage flags e.g. -fcoverage-mapping for gcc # Compiler-specific coverage flags e.g. -fcoverage-mapping for gcc
option(WITH_COVERAGE "Profile the resulting binary/binaries" OFF) option(WITH_COVERAGE "Profile the resulting binary/binaries" OFF)
@ -512,6 +518,7 @@ include (cmake/find/fastops.cmake)
include (cmake/find/odbc.cmake) include (cmake/find/odbc.cmake)
include (cmake/find/rocksdb.cmake) include (cmake/find/rocksdb.cmake)
include (cmake/find/libpqxx.cmake) include (cmake/find/libpqxx.cmake)
include (cmake/find/nanodbc.cmake)
include (cmake/find/nuraft.cmake) include (cmake/find/nuraft.cmake)

View File

@ -7,8 +7,7 @@
#include <condition_variable> #include <condition_variable>
#include <common/defines.h> #include <common/defines.h>
#include <common/MoveOrCopyIfThrow.h>
#include <Common/MoveOrCopyIfThrow.h>
/** Pool for limited size objects that cannot be used from different threads simultaneously. /** Pool for limited size objects that cannot be used from different threads simultaneously.
* The main use case is to have fixed size of objects that can be reused in difference threads during their lifetime * The main use case is to have fixed size of objects that can be reused in difference threads during their lifetime

View File

@ -271,9 +271,13 @@ struct integer<Bits, Signed>::_impl
/// As to_Integral does a static_cast to int64_t, it may result in UB. /// As to_Integral does a static_cast to int64_t, it may result in UB.
/// The necessary check here is that long double has enough significant (mantissa) bits to store the /// The necessary check here is that long double has enough significant (mantissa) bits to store the
/// int64_t max value precisely. /// int64_t max value precisely.
//TODO Be compatible with Apple aarch64
#if not (defined(__APPLE__) && defined(__aarch64__))
static_assert(LDBL_MANT_DIG >= 64, static_assert(LDBL_MANT_DIG >= 64,
"On your system long double has less than 64 precision bits," "On your system long double has less than 64 precision bits,"
"which may result in UB when initializing double from int64_t"); "which may result in UB when initializing double from int64_t");
#endif
if ((rhs > 0 && rhs < static_cast<long double>(max_int)) || (rhs < 0 && rhs > static_cast<long double>(min_int))) if ((rhs > 0 && rhs < static_cast<long double>(max_int)) || (rhs < 0 && rhs > static_cast<long double>(min_int)))
{ {

View File

@ -12,7 +12,8 @@
/// ///
/// NOTE: it should be used with caution. /// NOTE: it should be used with caution.
#define SCOPE_EXIT_MEMORY(...) SCOPE_EXIT( \ #define SCOPE_EXIT_MEMORY(...) SCOPE_EXIT( \
MemoryTracker::LockExceptionInThread lock_memory_tracker; \ MemoryTracker::LockExceptionInThread \
lock_memory_tracker(VariableContext::Global); \
__VA_ARGS__; \ __VA_ARGS__; \
) )
@ -56,7 +57,8 @@
#define SCOPE_EXIT_MEMORY_SAFE(...) SCOPE_EXIT( \ #define SCOPE_EXIT_MEMORY_SAFE(...) SCOPE_EXIT( \
try \ try \
{ \ { \
MemoryTracker::LockExceptionInThread lock_memory_tracker; \ MemoryTracker::LockExceptionInThread \
lock_memory_tracker(VariableContext::Global); \
__VA_ARGS__; \ __VA_ARGS__; \
} \ } \
catch (...) \ catch (...) \

View File

@ -1,7 +1,7 @@
if (CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64") if (CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64")
set (ARCH_AMD64 1) set (ARCH_AMD64 1)
endif () endif ()
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*|ARM64.*)")
set (ARCH_AARCH64 1) set (ARCH_AARCH64 1)
endif () endif ()
if (ARCH_AARCH64 OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm") if (ARCH_AARCH64 OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm")

View File

@ -4,6 +4,9 @@ set (DEFAULT_LIBS "${DEFAULT_LIBS} ${COVERAGE_OPTION} -lc -lm -lpthread -ldl")
if (COMPILER_GCC) if (COMPILER_GCC)
set (DEFAULT_LIBS "${DEFAULT_LIBS} -lgcc_eh") set (DEFAULT_LIBS "${DEFAULT_LIBS} -lgcc_eh")
if (ARCH_AARCH64)
set (DEFAULT_LIBS "${DEFAULT_LIBS} -lgcc")
endif ()
endif () endif ()
message(STATUS "Default libraries: ${DEFAULT_LIBS}") message(STATUS "Default libraries: ${DEFAULT_LIBS}")

View File

@ -0,0 +1,14 @@
set (CMAKE_SYSTEM_NAME "Darwin")
set (CMAKE_SYSTEM_PROCESSOR "aarch64")
set (CMAKE_C_COMPILER_TARGET "aarch64-apple-darwin")
set (CMAKE_CXX_COMPILER_TARGET "aarch64-apple-darwin")
set (CMAKE_ASM_COMPILER_TARGET "aarch64-apple-darwin")
set (CMAKE_OSX_SYSROOT "${CMAKE_CURRENT_LIST_DIR}/../toolchain/darwin-aarch64")
set (CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # disable linkage check - it doesn't work in CMake
set (HAS_PRE_1970_EXITCODE "0" CACHE STRING "Result from TRY_RUN" FORCE)
set (HAS_PRE_1970_EXITCODE__TRYRUN_OUTPUT "" CACHE STRING "Output from TRY_RUN" FORCE)
set (HAS_POST_2038_EXITCODE "0" CACHE STRING "Result from TRY_RUN" FORCE)
set (HAS_POST_2038_EXITCODE__TRYRUN_OUTPUT "" CACHE STRING "Output from TRY_RUN" FORCE)

View File

@ -64,7 +64,8 @@ if (NOT OPENLDAP_FOUND AND NOT MISSING_INTERNAL_LDAP_LIBRARY)
( "${_system_name}" STREQUAL "linux" AND "${_system_processor}" STREQUAL "aarch64" ) OR ( "${_system_name}" STREQUAL "linux" AND "${_system_processor}" STREQUAL "aarch64" ) OR
( "${_system_name}" STREQUAL "linux" AND "${_system_processor}" STREQUAL "ppc64le" ) OR ( "${_system_name}" STREQUAL "linux" AND "${_system_processor}" STREQUAL "ppc64le" ) OR
( "${_system_name}" STREQUAL "freebsd" AND "${_system_processor}" STREQUAL "x86_64" ) OR ( "${_system_name}" STREQUAL "freebsd" AND "${_system_processor}" STREQUAL "x86_64" ) OR
( "${_system_name}" STREQUAL "darwin" AND "${_system_processor}" STREQUAL "x86_64" ) ( "${_system_name}" STREQUAL "darwin" AND "${_system_processor}" STREQUAL "x86_64" ) OR
( "${_system_name}" STREQUAL "darwin" AND "${_system_processor}" STREQUAL "aarch64" )
) )
set (_ldap_supported_platform TRUE) set (_ldap_supported_platform TRUE)
endif () endif ()

35
cmake/find/nanodbc.cmake Normal file
View File

@ -0,0 +1,35 @@
option(ENABLE_NANODBC "Enalbe nanodbc" ${ENABLE_LIBRARIES})
if (NOT ENABLE_NANODBC)
set (USE_ODBC 0)
return()
endif()
if (NOT ENABLE_ODBC)
set (USE_NANODBC 0)
message (STATUS "Using nanodbc=${USE_NANODBC}")
return()
endif()
if (NOT EXISTS "${ClickHouse_SOURCE_DIR}/contrib/nanodbc/CMakeLists.txt")
message (WARNING "submodule contrib/nanodbc is missing. to fix try run: \n git submodule update --init --recursive")
message (${RECONFIGURE_MESSAGE_LEVEL} "Can't find internal nanodbc library")
set (USE_NANODBC 0)
return()
endif()
if (NOT EXISTS "${ClickHouse_SOURCE_DIR}/contrib/unixodbc/include")
message (ERROR "submodule contrib/unixodbc is missing. to fix try run: \n git submodule update --init --recursive")
message (${RECONFIGURE_MESSAGE_LEVEL} "Can't find internal unixodbc needed for nanodbc")
set (USE_NANODBC 0)
return()
endif()
set (USE_NANODBC 1)
set (NANODBC_LIBRARY nanodbc)
set (NANODBC_INCLUDE_DIR "${ClickHouse_SOURCE_DIR}/contrib/nanodbc/nanodbce")
message (STATUS "Using nanodbc=${USE_NANODBC}: ${NANODBC_INCLUDE_DIR} : ${NANODBC_LIBRARY}")
message (STATUS "Using unixodbc")

View File

@ -1,3 +1,7 @@
if (OS_DARWIN AND ARCH_AARCH64)
set (ENABLE_ROCKSDB OFF CACHE INTERNAL "")
endif()
option(ENABLE_ROCKSDB "Enable ROCKSDB" ${ENABLE_LIBRARIES}) option(ENABLE_ROCKSDB "Enable ROCKSDB" ${ENABLE_LIBRARIES})
if (NOT ENABLE_ROCKSDB) if (NOT ENABLE_ROCKSDB)

View File

@ -96,14 +96,8 @@ if (USE_INTERNAL_ZLIB_LIBRARY)
add_subdirectory (${INTERNAL_ZLIB_NAME}) add_subdirectory (${INTERNAL_ZLIB_NAME})
# We should use same defines when including zlib.h as used when zlib compiled # We should use same defines when including zlib.h as used when zlib compiled
target_compile_definitions (zlib PUBLIC ZLIB_COMPAT WITH_GZFILEOP) target_compile_definitions (zlib PUBLIC ZLIB_COMPAT WITH_GZFILEOP)
if (TARGET zlibstatic)
target_compile_definitions (zlibstatic PUBLIC ZLIB_COMPAT WITH_GZFILEOP)
endif ()
if (ARCH_AMD64 OR ARCH_AARCH64) if (ARCH_AMD64 OR ARCH_AARCH64)
target_compile_definitions (zlib PUBLIC X86_64 UNALIGNED_OK) target_compile_definitions (zlib PUBLIC X86_64 UNALIGNED_OK)
if (TARGET zlibstatic)
target_compile_definitions (zlibstatic PUBLIC X86_64 UNALIGNED_OK)
endif ()
endif () endif ()
endif () endif ()
@ -326,6 +320,10 @@ if (USE_LIBPQXX)
add_subdirectory (libpqxx-cmake) add_subdirectory (libpqxx-cmake)
endif() endif()
if (USE_NANODBC)
add_subdirectory (nanodbc-cmake)
endif()
if (USE_NURAFT) if (USE_NURAFT)
add_subdirectory(nuraft-cmake) add_subdirectory(nuraft-cmake)
endif() endif()

2
contrib/NuRaft vendored

@ -1 +1 @@
Subproject commit c35819f2c8a378d4ba88cc930c17bc20aeb875eb Subproject commit d2feb5978b979729a07c3ca76eaa4ab94cef4ceb

2
contrib/boost vendored

@ -1 +1 @@
Subproject commit ee24fa55bc46e4d2ce7d0d052cc5a0d9b1be8c36 Subproject commit a8d43d3142cc6b26fc55bec33f7f6edb1156ab7a

View File

@ -1,10 +1,13 @@
if (SANITIZE OR NOT (ARCH_AMD64 OR ARCH_ARM OR ARCH_PPC64LE) OR NOT (OS_LINUX OR OS_FREEBSD OR OS_DARWIN)) if (SANITIZE OR NOT (
((OS_LINUX OR OS_FREEBSD) AND (ARCH_AMD64 OR ARCH_ARM OR ARCH_PPC64LE)) OR
(OS_DARWIN AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
))
if (ENABLE_JEMALLOC) if (ENABLE_JEMALLOC)
message (${RECONFIGURE_MESSAGE_LEVEL} message (${RECONFIGURE_MESSAGE_LEVEL}
"jemalloc is disabled implicitly: it doesn't work with sanitizers and can only be used with x86_64, aarch64 or ppc64le on linux or freebsd.") "jemalloc is disabled implicitly: it doesn't work with sanitizers and can only be used with x86_64, aarch64, or ppc64le Linux or FreeBSD builds and RelWithDebInfo macOS builds.")
endif() endif ()
set (ENABLE_JEMALLOC OFF) set (ENABLE_JEMALLOC OFF)
else() else ()
option (ENABLE_JEMALLOC "Enable jemalloc allocator" ${ENABLE_LIBRARIES}) option (ENABLE_JEMALLOC "Enable jemalloc allocator" ${ENABLE_LIBRARIES})
endif () endif ()
@ -34,9 +37,9 @@ if (OS_LINUX)
# avoid spurious latencies and additional work associated with # avoid spurious latencies and additional work associated with
# MADV_DONTNEED. See # MADV_DONTNEED. See
# https://github.com/ClickHouse/ClickHouse/issues/11121 for motivation. # https://github.com/ClickHouse/ClickHouse/issues/11121 for motivation.
set (JEMALLOC_CONFIG_MALLOC_CONF "percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:10000") set (JEMALLOC_CONFIG_MALLOC_CONF "percpu_arena:percpu,oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000")
else() else()
set (JEMALLOC_CONFIG_MALLOC_CONF "oversize_threshold:0,muzzy_decay_ms:10000") set (JEMALLOC_CONFIG_MALLOC_CONF "oversize_threshold:0,muzzy_decay_ms:5000,dirty_decay_ms:5000")
endif() endif()
# CACHE variable is empty, to allow changing defaults without necessity # CACHE variable is empty, to allow changing defaults without necessity
# to purge cache # to purge cache

View File

@ -42,7 +42,7 @@
* total number of bits in a pointer, e.g. on x64, for which the uppermost 16 * total number of bits in a pointer, e.g. on x64, for which the uppermost 16
* bits are the same as bit 47. * bits are the same as bit 47.
*/ */
#define LG_VADDR 48 #define LG_VADDR 64
/* Defined if C11 atomics are available. */ /* Defined if C11 atomics are available. */
#define JEMALLOC_C11_ATOMICS 1 #define JEMALLOC_C11_ATOMICS 1
@ -101,11 +101,6 @@
*/ */
#define JEMALLOC_HAVE_MACH_ABSOLUTE_TIME 1 #define JEMALLOC_HAVE_MACH_ABSOLUTE_TIME 1
/*
* Defined if clock_gettime(CLOCK_REALTIME, ...) is available.
*/
#define JEMALLOC_HAVE_CLOCK_REALTIME 1
/* /*
* Defined if _malloc_thread_cleanup() exists. At least in the case of * Defined if _malloc_thread_cleanup() exists. At least in the case of
* FreeBSD, pthread_key_create() allocates, which if used during malloc * FreeBSD, pthread_key_create() allocates, which if used during malloc
@ -181,14 +176,14 @@
/* #undef LG_QUANTUM */ /* #undef LG_QUANTUM */
/* One page is 2^LG_PAGE bytes. */ /* One page is 2^LG_PAGE bytes. */
#define LG_PAGE 16 #define LG_PAGE 14
/* /*
* One huge page is 2^LG_HUGEPAGE bytes. Note that this is defined even if the * One huge page is 2^LG_HUGEPAGE bytes. Note that this is defined even if the
* system does not explicitly support huge pages; system calls that require * system does not explicitly support huge pages; system calls that require
* explicit huge page support are separately configured. * explicit huge page support are separately configured.
*/ */
#define LG_HUGEPAGE 29 #define LG_HUGEPAGE 21
/* /*
* If defined, adjacent virtual memory mappings with identical attributes * If defined, adjacent virtual memory mappings with identical attributes
@ -356,7 +351,7 @@
/* #undef JEMALLOC_EXPORT */ /* #undef JEMALLOC_EXPORT */
/* config.malloc_conf options string. */ /* config.malloc_conf options string. */
#define JEMALLOC_CONFIG_MALLOC_CONF "@JEMALLOC_CONFIG_MALLOC_CONF@" #define JEMALLOC_CONFIG_MALLOC_CONF ""
/* If defined, jemalloc takes the malloc/free/etc. symbol names. */ /* If defined, jemalloc takes the malloc/free/etc. symbol names. */
/* #undef JEMALLOC_IS_MALLOC */ /* #undef JEMALLOC_IS_MALLOC */

View File

@ -66,7 +66,7 @@
#cmakedefine WITH_SASL_OAUTHBEARER 1 #cmakedefine WITH_SASL_OAUTHBEARER 1
#cmakedefine WITH_SASL_CYRUS 1 #cmakedefine WITH_SASL_CYRUS 1
// crc32chw // crc32chw
#if !defined(__PPC__) && (!defined(__aarch64__) || defined(__ARM_FEATURE_CRC32)) #if !defined(__PPC__) && (!defined(__aarch64__) || defined(__ARM_FEATURE_CRC32)) && !(defined(__aarch64__) && defined(__APPLE__))
#define WITH_CRC32C_HW 1 #define WITH_CRC32C_HW 1
#endif #endif
// regex // regex

1
contrib/nanodbc vendored Submodule

@ -0,0 +1 @@
Subproject commit 9fc459675515d491401727ec67fca38db721f28c

View File

@ -0,0 +1,14 @@
set (LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/nanodbc)
if (NOT TARGET unixodbc)
message(FATAL_ERROR "Configuration error: unixodbc is not a target")
endif()
set (SRCS
${LIBRARY_DIR}/nanodbc/nanodbc.cpp
)
add_library(nanodbc ${SRCS})
target_link_libraries (nanodbc PUBLIC unixodbc)
target_include_directories (nanodbc SYSTEM PUBLIC ${LIBRARY_DIR}/)

View File

@ -0,0 +1,63 @@
/* include/lber_types.h. Generated from lber_types.hin by configure. */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/*
* LBER types
*/
#ifndef _LBER_TYPES_H
#define _LBER_TYPES_H
#include <ldap_cdefs.h>
LDAP_BEGIN_DECL
/* LBER boolean, enum, integers (32 bits or larger) */
#define LBER_INT_T int
/* LBER tags (32 bits or larger) */
#define LBER_TAG_T long
/* LBER socket descriptor */
#define LBER_SOCKET_T int
/* LBER lengths (32 bits or larger) */
#define LBER_LEN_T long
/* ------------------------------------------------------------ */
/* booleans, enumerations, and integers */
typedef LBER_INT_T ber_int_t;
/* signed and unsigned versions */
typedef signed LBER_INT_T ber_sint_t;
typedef unsigned LBER_INT_T ber_uint_t;
/* tags */
typedef unsigned LBER_TAG_T ber_tag_t;
/* "socket" descriptors */
typedef LBER_SOCKET_T ber_socket_t;
/* lengths */
typedef unsigned LBER_LEN_T ber_len_t;
/* signed lengths */
typedef signed LBER_LEN_T ber_slen_t;
LDAP_END_DECL
#endif /* _LBER_TYPES_H */

View File

@ -0,0 +1,74 @@
/* include/ldap_config.h. Generated from ldap_config.hin by configure. */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/*
* This file works in conjunction with OpenLDAP configure system.
* If you do no like the values below, adjust your configure options.
*/
#ifndef _LDAP_CONFIG_H
#define _LDAP_CONFIG_H
/* directory separator */
#ifndef LDAP_DIRSEP
#ifndef _WIN32
#define LDAP_DIRSEP "/"
#else
#define LDAP_DIRSEP "\\"
#endif
#endif
/* directory for temporary files */
#if defined(_WIN32)
# define LDAP_TMPDIR "C:\\." /* we don't have much of a choice */
#elif defined( _P_tmpdir )
# define LDAP_TMPDIR _P_tmpdir
#elif defined( P_tmpdir )
# define LDAP_TMPDIR P_tmpdir
#elif defined( _PATH_TMPDIR )
# define LDAP_TMPDIR _PATH_TMPDIR
#else
# define LDAP_TMPDIR LDAP_DIRSEP "tmp"
#endif
/* directories */
#ifndef LDAP_BINDIR
#define LDAP_BINDIR "/tmp/ldap-prefix/bin"
#endif
#ifndef LDAP_SBINDIR
#define LDAP_SBINDIR "/tmp/ldap-prefix/sbin"
#endif
#ifndef LDAP_DATADIR
#define LDAP_DATADIR "/tmp/ldap-prefix/share/openldap"
#endif
#ifndef LDAP_SYSCONFDIR
#define LDAP_SYSCONFDIR "/tmp/ldap-prefix/etc/openldap"
#endif
#ifndef LDAP_LIBEXECDIR
#define LDAP_LIBEXECDIR "/tmp/ldap-prefix/libexec"
#endif
#ifndef LDAP_MODULEDIR
#define LDAP_MODULEDIR "/tmp/ldap-prefix/libexec/openldap"
#endif
#ifndef LDAP_RUNDIR
#define LDAP_RUNDIR "/tmp/ldap-prefix/var"
#endif
#ifndef LDAP_LOCALEDIR
#define LDAP_LOCALEDIR ""
#endif
#endif /* _LDAP_CONFIG_H */

View File

@ -0,0 +1,61 @@
/* include/ldap_features.h. Generated from ldap_features.hin by configure. */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2020 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/*
* LDAP Features
*/
#ifndef _LDAP_FEATURES_H
#define _LDAP_FEATURES_H 1
/* OpenLDAP API version macros */
#define LDAP_VENDOR_VERSION 20501
#define LDAP_VENDOR_VERSION_MAJOR 2
#define LDAP_VENDOR_VERSION_MINOR 5
#define LDAP_VENDOR_VERSION_PATCH X
/*
** WORK IN PROGRESS!
**
** OpenLDAP reentrancy/thread-safeness should be dynamically
** checked using ldap_get_option().
**
** The -lldap implementation is not thread-safe.
**
** The -lldap_r implementation is:
** LDAP_API_FEATURE_THREAD_SAFE (basic thread safety)
** but also be:
** LDAP_API_FEATURE_SESSION_THREAD_SAFE
** LDAP_API_FEATURE_OPERATION_THREAD_SAFE
**
** The preprocessor flag LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE
** can be used to determine if -lldap_r is available at compile
** time. You must define LDAP_THREAD_SAFE if and only if you
** link with -lldap_r.
**
** If you fail to define LDAP_THREAD_SAFE when linking with
** -lldap_r or define LDAP_THREAD_SAFE when linking with -lldap,
** provided header definitions and declarations may be incorrect.
**
*/
/* is -lldap_r available or not */
#define LDAP_API_FEATURE_X_OPENLDAP_THREAD_SAFE 1
/* LDAP v2 Referrals */
/* #undef LDAP_API_FEATURE_X_OPENLDAP_V2_REFERRALS */
#endif /* LDAP_FEATURES */

File diff suppressed because it is too large Load Diff

View File

@ -233,3 +233,10 @@ else ()
message (STATUS "Using Poco::Foundation: ${LIBRARY_POCO_FOUNDATION} ${INCLUDE_POCO_FOUNDATION}") message (STATUS "Using Poco::Foundation: ${LIBRARY_POCO_FOUNDATION} ${INCLUDE_POCO_FOUNDATION}")
endif () endif ()
if(OS_DARWIN AND ARCH_AARCH64)
target_compile_definitions (_poco_foundation
PRIVATE
POCO_NO_STAT64
)
endif()

View File

@ -142,14 +142,14 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
endif(HAS_ALTIVEC) endif(HAS_ALTIVEC)
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64") endif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
CHECK_C_COMPILER_FLAG("-march=armv8-a+crc+crypto" HAS_ARMV8_CRC) CHECK_C_COMPILER_FLAG("-march=armv8-a+crc+crypto" HAS_ARMV8_CRC)
if(HAS_ARMV8_CRC) if(HAS_ARMV8_CRC)
message(STATUS " HAS_ARMV8_CRC yes") message(STATUS " HAS_ARMV8_CRC yes")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a+crc+crypto -Wno-unused-function") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a+crc+crypto -Wno-unused-function")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a+crc+crypto -Wno-unused-function") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a+crc+crypto -Wno-unused-function")
endif(HAS_ARMV8_CRC) endif(HAS_ARMV8_CRC)
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") endif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
include(CheckCXXSourceCompiles) include(CheckCXXSourceCompiles)

2
contrib/zlib-ng vendored

@ -1 +1 @@
Subproject commit 6fd1846c8b8f59436fe2dd752d0f316ddbb64df6 Subproject commit 4039bb4623905e73c6e32a0c022f144bab87b2b3

View File

@ -3,4 +3,3 @@ usr/bin/clickhouse-odbc-bridge
usr/bin/clickhouse-library-bridge usr/bin/clickhouse-library-bridge
usr/bin/clickhouse-extract-from-config usr/bin/clickhouse-extract-from-config
usr/share/bash-completion/completions usr/share/bash-completion/completions
etc/security/limits.d/clickhouse.conf

View File

@ -1,16 +0,0 @@
#!/bin/sh -e
test -f /usr/share/debconf/confmodule && . /usr/share/debconf/confmodule
db_fget clickhouse-server/default-password seen || true
password_seen="$RET"
if [ "$1" = "reconfigure" ]; then
password_seen=false
fi
if [ "$password_seen" != "true" ]; then
db_input high clickhouse-server/default-password || true
db_go || true
fi
db_go || true

View File

@ -23,11 +23,13 @@ if [ ! -f "/etc/debian_version" ]; then
fi fi
if [ "$1" = configure ] || [ -n "$not_deb_os" ]; then if [ "$1" = configure ] || [ -n "$not_deb_os" ]; then
${CLICKHOUSE_GENERIC_PROGRAM} install --user "${CLICKHOUSE_USER}" --group "${CLICKHOUSE_GROUP}" --pid-path "${CLICKHOUSE_PIDDIR}" --config-path "${CLICKHOUSE_CONFDIR}" --binary-path "${CLICKHOUSE_BINDIR}" --log-path "${CLICKHOUSE_LOGDIR}" --data-path "${CLICKHOUSE_DATADIR}"
if [ -x "/bin/systemctl" ] && [ -f /etc/systemd/system/clickhouse-server.service ] && [ -d /run/systemd/system ]; then if [ -x "/bin/systemctl" ] && [ -f /etc/systemd/system/clickhouse-server.service ] && [ -d /run/systemd/system ]; then
# if old rc.d service present - remove it # if old rc.d service present - remove it
if [ -x "/etc/init.d/clickhouse-server" ] && [ -x "/usr/sbin/update-rc.d" ]; then if [ -x "/etc/init.d/clickhouse-server" ] && [ -x "/usr/sbin/update-rc.d" ]; then
/usr/sbin/update-rc.d clickhouse-server remove /usr/sbin/update-rc.d clickhouse-server remove
echo "ClickHouse init script has migrated to systemd. Please manually stop old server and restart the service: sudo killall clickhouse-server && sleep 5 && sudo service clickhouse-server restart"
fi fi
/bin/systemctl daemon-reload /bin/systemctl daemon-reload
@ -38,10 +40,8 @@ if [ "$1" = configure ] || [ -n "$not_deb_os" ]; then
if [ -x "/usr/sbin/update-rc.d" ]; then if [ -x "/usr/sbin/update-rc.d" ]; then
/usr/sbin/update-rc.d clickhouse-server defaults 19 19 >/dev/null || exit $? /usr/sbin/update-rc.d clickhouse-server defaults 19 19 >/dev/null || exit $?
else else
echo # TODO [ "$OS" = "rhel" ] || [ "$OS" = "centos" ] || [ "$OS" = "fedora" ] echo # Other OS
fi fi
fi fi
fi fi
${CLICKHOUSE_GENERIC_PROGRAM} install --user "${CLICKHOUSE_USER}" --group "${CLICKHOUSE_GROUP}" --pid-path "${CLICKHOUSE_PIDDIR}" --config-path "${CLICKHOUSE_CONFDIR}" --binary-path "${CLICKHOUSE_BINDIR}" --log-path "${CLICKHOUSE_LOGDIR}" --data-path "${CLICKHOUSE_DATADIR}"
fi fi

View File

@ -1,8 +0,0 @@
#!/bin/sh
if [ "$1" = "upgrade" ]; then
# Return etc/cron.d/clickhouse-server to original state
service clickhouse-server disable_cron ||:
fi
#DEBHELPER#

View File

@ -1,6 +0,0 @@
#!/bin/sh
if [ "$1" = "upgrade" ] || [ "$1" = "remove" ]; then
# Return etc/cron.d/clickhouse-server to original state
service clickhouse-server disable_cron ||:
fi

View File

@ -1,3 +0,0 @@
Template: clickhouse-server/default-password
Type: password
Description: Enter password for default user:

View File

@ -1,2 +0,0 @@
clickhouse soft nofile 262144
clickhouse hard nofile 262144

3
debian/rules vendored
View File

@ -113,9 +113,6 @@ override_dh_install:
ln -sf clickhouse-server.docs debian/clickhouse-client.docs ln -sf clickhouse-server.docs debian/clickhouse-client.docs
ln -sf clickhouse-server.docs debian/clickhouse-common-static.docs ln -sf clickhouse-server.docs debian/clickhouse-common-static.docs
mkdir -p $(DESTDIR)/etc/security/limits.d
cp debian/clickhouse.limits $(DESTDIR)/etc/security/limits.d/clickhouse.conf
# systemd compatibility # systemd compatibility
mkdir -p $(DESTDIR)/etc/systemd/system/ mkdir -p $(DESTDIR)/etc/systemd/system/
cp debian/clickhouse-server.service $(DESTDIR)/etc/systemd/system/ cp debian/clickhouse-server.service $(DESTDIR)/etc/systemd/system/

2
debian/watch vendored
View File

@ -1,6 +1,6 @@
version=4 version=4
opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)-stable\.tar\.gz%clickhouse-$1.tar.gz%" \ opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)-stable\.tar\.gz%clickhouse-$1.tar.gz%" \
https://github.com/yandex/clickhouse/tags \ https://github.com/ClickHouse/ClickHouse/tags \
(?:.*?/)?v?(\d[\d.]*)-stable\.tar\.gz debian uupdate (?:.*?/)?v?(\d[\d.]*)-stable\.tar\.gz debian uupdate

View File

@ -300,6 +300,7 @@ function run_tests
01663_aes_msan # Depends on OpenSSL 01663_aes_msan # Depends on OpenSSL
01667_aes_args_check # Depends on OpenSSL 01667_aes_args_check # Depends on OpenSSL
01776_decrypt_aead_size_check # Depends on OpenSSL 01776_decrypt_aead_size_check # Depends on OpenSSL
01811_filter_by_null # Depends on OpenSSL
01281_unsucceeded_insert_select_queries_counter 01281_unsucceeded_insert_select_queries_counter
01292_create_user 01292_create_user
01294_lazy_database_concurrent 01294_lazy_database_concurrent
@ -365,6 +366,12 @@ function run_tests
# JSON functions # JSON functions
01666_blns 01666_blns
# Requires postgresql-client
01802_test_postgresql_protocol_with_row_policy
# Depends on AWS
01801_s3_cluster
) )
(time clickhouse-test --hung-check -j 8 --order=random --use-skip-list --no-long --testname --shard --zookeeper --skip "${TESTS_TO_SKIP[@]}" -- "$FASTTEST_FOCUS" 2>&1 ||:) | ts '%Y-%m-%d %H:%M:%S' | tee "$FASTTEST_OUTPUT/test_log.txt" (time clickhouse-test --hung-check -j 8 --order=random --use-skip-list --no-long --testname --shard --zookeeper --skip "${TESTS_TO_SKIP[@]}" -- "$FASTTEST_FOCUS" 2>&1 ||:) | ts '%Y-%m-%d %H:%M:%S' | tee "$FASTTEST_OUTPUT/test_log.txt"

View File

@ -21,14 +21,14 @@ function start()
-- --path /var/lib/clickhouse1/ --logger.stderr /var/log/clickhouse-server/stderr1.log \ -- --path /var/lib/clickhouse1/ --logger.stderr /var/log/clickhouse-server/stderr1.log \
--logger.log /var/log/clickhouse-server/clickhouse-server1.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server1.err.log \ --logger.log /var/log/clickhouse-server/clickhouse-server1.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server1.err.log \
--tcp_port 19000 --tcp_port_secure 19440 --http_port 18123 --https_port 18443 --interserver_http_port 19009 --tcp_with_proxy_port 19010 \ --tcp_port 19000 --tcp_port_secure 19440 --http_port 18123 --https_port 18443 --interserver_http_port 19009 --tcp_with_proxy_port 19010 \
--mysql_port 19004 \ --mysql_port 19004 --postgresql_port 19005 \
--keeper_server.tcp_port 19181 --keeper_server.server_id 2 --keeper_server.tcp_port 19181 --keeper_server.server_id 2
sudo -E -u clickhouse /usr/bin/clickhouse server --config /etc/clickhouse-server2/config.xml --daemon \ sudo -E -u clickhouse /usr/bin/clickhouse server --config /etc/clickhouse-server2/config.xml --daemon \
-- --path /var/lib/clickhouse2/ --logger.stderr /var/log/clickhouse-server/stderr2.log \ -- --path /var/lib/clickhouse2/ --logger.stderr /var/log/clickhouse-server/stderr2.log \
--logger.log /var/log/clickhouse-server/clickhouse-server2.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server2.err.log \ --logger.log /var/log/clickhouse-server/clickhouse-server2.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server2.err.log \
--tcp_port 29000 --tcp_port_secure 29440 --http_port 28123 --https_port 28443 --interserver_http_port 29009 --tcp_with_proxy_port 29010 \ --tcp_port 29000 --tcp_port_secure 29440 --http_port 28123 --https_port 28443 --interserver_http_port 29009 --tcp_with_proxy_port 29010 \
--mysql_port 29004 \ --mysql_port 29004 --postgresql_port 29005 \
--keeper_server.tcp_port 29181 --keeper_server.server_id 3 --keeper_server.tcp_port 29181 --keeper_server.server_id 3
fi fi

View File

@ -28,7 +28,8 @@ RUN apt-get update -y \
tree \ tree \
unixodbc \ unixodbc \
wget \ wget \
mysql-client=5.7* mysql-client=5.7* \
postgresql-client
RUN pip3 install numpy scipy pandas RUN pip3 install numpy scipy pandas

View File

@ -44,7 +44,7 @@ if [[ -n "$USE_DATABASE_REPLICATED" ]] && [[ "$USE_DATABASE_REPLICATED" -eq 1 ]]
-- --path /var/lib/clickhouse1/ --logger.stderr /var/log/clickhouse-server/stderr1.log \ -- --path /var/lib/clickhouse1/ --logger.stderr /var/log/clickhouse-server/stderr1.log \
--logger.log /var/log/clickhouse-server/clickhouse-server1.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server1.err.log \ --logger.log /var/log/clickhouse-server/clickhouse-server1.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server1.err.log \
--tcp_port 19000 --tcp_port_secure 19440 --http_port 18123 --https_port 18443 --interserver_http_port 19009 --tcp_with_proxy_port 19010 \ --tcp_port 19000 --tcp_port_secure 19440 --http_port 18123 --https_port 18443 --interserver_http_port 19009 --tcp_with_proxy_port 19010 \
--mysql_port 19004 \ --mysql_port 19004 --postgresql_port 19005 \
--keeper_server.tcp_port 19181 --keeper_server.server_id 2 \ --keeper_server.tcp_port 19181 --keeper_server.server_id 2 \
--macros.replica r2 # It doesn't work :( --macros.replica r2 # It doesn't work :(
@ -52,7 +52,7 @@ if [[ -n "$USE_DATABASE_REPLICATED" ]] && [[ "$USE_DATABASE_REPLICATED" -eq 1 ]]
-- --path /var/lib/clickhouse2/ --logger.stderr /var/log/clickhouse-server/stderr2.log \ -- --path /var/lib/clickhouse2/ --logger.stderr /var/log/clickhouse-server/stderr2.log \
--logger.log /var/log/clickhouse-server/clickhouse-server2.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server2.err.log \ --logger.log /var/log/clickhouse-server/clickhouse-server2.log --logger.errorlog /var/log/clickhouse-server/clickhouse-server2.err.log \
--tcp_port 29000 --tcp_port_secure 29440 --http_port 28123 --https_port 28443 --interserver_http_port 29009 --tcp_with_proxy_port 29010 \ --tcp_port 29000 --tcp_port_secure 29440 --http_port 28123 --https_port 28443 --interserver_http_port 29009 --tcp_with_proxy_port 29010 \
--mysql_port 29004 \ --mysql_port 29004 --postgresql_port 29005 \
--keeper_server.tcp_port 29181 --keeper_server.server_id 3 \ --keeper_server.tcp_port 29181 --keeper_server.server_id 3 \
--macros.shard s2 # It doesn't work :( --macros.shard s2 # It doesn't work :(
@ -112,10 +112,13 @@ if [[ -n "$WITH_COVERAGE" ]] && [[ "$WITH_COVERAGE" -eq 1 ]]; then
fi fi
tar -chf /test_output/text_log_dump.tar /var/lib/clickhouse/data/system/text_log ||: tar -chf /test_output/text_log_dump.tar /var/lib/clickhouse/data/system/text_log ||:
tar -chf /test_output/query_log_dump.tar /var/lib/clickhouse/data/system/query_log ||: tar -chf /test_output/query_log_dump.tar /var/lib/clickhouse/data/system/query_log ||:
tar -chf /test_output/coordination.tar /var/lib/clickhouse/coordination ||:
if [[ -n "$USE_DATABASE_REPLICATED" ]] && [[ "$USE_DATABASE_REPLICATED" -eq 1 ]]; then if [[ -n "$USE_DATABASE_REPLICATED" ]] && [[ "$USE_DATABASE_REPLICATED" -eq 1 ]]; then
pigz < /var/log/clickhouse-server/clickhouse-server1.log > /test_output/clickhouse-server1.log.gz ||: pigz < /var/log/clickhouse-server/clickhouse-server1.log > /test_output/clickhouse-server1.log.gz ||:
pigz < /var/log/clickhouse-server/clickhouse-server2.log > /test_output/clickhouse-server2.log.gz ||: pigz < /var/log/clickhouse-server/clickhouse-server2.log > /test_output/clickhouse-server2.log.gz ||:
mv /var/log/clickhouse-server/stderr1.log /test_output/ ||: mv /var/log/clickhouse-server/stderr1.log /test_output/ ||:
mv /var/log/clickhouse-server/stderr2.log /test_output/ ||: mv /var/log/clickhouse-server/stderr2.log /test_output/ ||:
tar -chf /test_output/coordination1.tar /var/lib/clickhouse1/coordination ||:
tar -chf /test_output/coordination2.tar /var/lib/clickhouse2/coordination ||:
fi fi

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from multiprocessing import cpu_count from multiprocessing import cpu_count
from subprocess import Popen, call, STDOUT from subprocess import Popen, call, check_output, STDOUT
import os import os
import sys import sys
import shutil import shutil
@ -85,10 +85,27 @@ def prepare_for_hung_check():
# Issue #21004, live views are experimental, so let's just suppress it # Issue #21004, live views are experimental, so let's just suppress it
call("""clickhouse client -q "KILL QUERY WHERE upper(query) LIKE 'WATCH %'" """, shell=True, stderr=STDOUT) call("""clickhouse client -q "KILL QUERY WHERE upper(query) LIKE 'WATCH %'" """, shell=True, stderr=STDOUT)
# Wait for last queries to finish if any, not longer than 120 seconds # Kill other queries which known to be slow
# It's query from 01232_preparing_sets_race_condition_long, it may take up to 1000 seconds in slow builds
call("""clickhouse client -q "KILL QUERY WHERE query LIKE 'insert into tableB select %'" """, shell=True, stderr=STDOUT)
# Long query from 00084_external_agregation
call("""clickhouse client -q "KILL QUERY WHERE query LIKE 'SELECT URL, uniq(SearchPhrase) AS u FROM test.hits GROUP BY URL ORDER BY u %'" """, shell=True, stderr=STDOUT)
# Wait for last queries to finish if any, not longer than 300 seconds
call("""clickhouse client -q "select sleepEachRow(( call("""clickhouse client -q "select sleepEachRow((
select maxOrDefault(120 - elapsed) + 1 from system.processes where query not like '%from system.processes%' and elapsed < 120 select maxOrDefault(300 - elapsed) + 1 from system.processes where query not like '%from system.processes%' and elapsed < 300
) / 120) from numbers(120) format Null" """, shell=True, stderr=STDOUT) ) / 300) from numbers(300) format Null" """, shell=True, stderr=STDOUT)
# Even if all clickhouse-test processes are finished, there are probably some sh scripts,
# which still run some new queries. Let's ignore them.
try:
query = """clickhouse client -q "SELECT count() FROM system.processes where where elapsed > 300" """
output = check_output(query, shell=True, stderr=STDOUT).decode('utf-8').strip()
if int(output) == 0:
return False
except:
pass
return True
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
@ -119,12 +136,12 @@ if __name__ == "__main__":
logging.info("All processes finished") logging.info("All processes finished")
if args.hung_check: if args.hung_check:
prepare_for_hung_check() have_long_running_queries = prepare_for_hung_check()
logging.info("Checking if some queries hung") logging.info("Checking if some queries hung")
cmd = "{} {} {}".format(args.test_cmd, "--hung-check", "00001_select_1") cmd = "{} {} {}".format(args.test_cmd, "--hung-check", "00001_select_1")
res = call(cmd, shell=True, stderr=STDOUT) res = call(cmd, shell=True, stderr=STDOUT)
hung_check_status = "No queries hung\tOK\n" hung_check_status = "No queries hung\tOK\n"
if res != 0: if res != 0 and have_long_running_queries:
logging.info("Hung check failed with exit code {}".format(res)) logging.info("Hung check failed with exit code {}".format(res))
hung_check_status = "Hung check failed\tFAIL\n" hung_check_status = "Hung check failed\tFAIL\n"
open(os.path.join(args.output_folder, "test_results.tsv"), 'w+').write(hung_check_status) open(os.path.join(args.output_folder, "test_results.tsv"), 'w+').write(hung_check_status)

View File

@ -5,12 +5,13 @@ toc_title: Build on Mac OS X
# How to Build ClickHouse on Mac OS X {#how-to-build-clickhouse-on-mac-os-x} # How to Build ClickHouse on Mac OS X {#how-to-build-clickhouse-on-mac-os-x}
Build should work on x86_64 (Intel) based macOS 10.15 (Catalina) and higher with recent Xcode's native AppleClang, or Homebrew's vanilla Clang or GCC compilers. Build should work on x86_64 (Intel) and arm64 (Apple Silicon) based macOS 10.15 (Catalina) and higher with recent Xcode's native AppleClang, or Homebrew's vanilla Clang or GCC compilers.
## Install Homebrew {#install-homebrew} ## Install Homebrew {#install-homebrew}
``` bash ``` bash
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# ...and follow the printed instructions on any additional steps required to complete the installation.
``` ```
## Install Xcode and Command Line Tools {#install-xcode-and-command-line-tools} ## Install Xcode and Command Line Tools {#install-xcode-and-command-line-tools}
@ -22,8 +23,8 @@ Open it at least once to accept the end-user license agreement and automatically
Then, make sure that the latest Comman Line Tools are installed and selected in the system: Then, make sure that the latest Comman Line Tools are installed and selected in the system:
``` bash ``` bash
$ sudo rm -rf /Library/Developer/CommandLineTools sudo rm -rf /Library/Developer/CommandLineTools
$ sudo xcode-select --install sudo xcode-select --install
``` ```
Reboot. Reboot.
@ -31,14 +32,15 @@ Reboot.
## Install Required Compilers, Tools, and Libraries {#install-required-compilers-tools-and-libraries} ## Install Required Compilers, Tools, and Libraries {#install-required-compilers-tools-and-libraries}
``` bash ``` bash
$ brew update brew update
$ brew install cmake ninja libtool gettext llvm gcc brew install cmake ninja libtool gettext llvm gcc
``` ```
## Checkout ClickHouse Sources {#checkout-clickhouse-sources} ## Checkout ClickHouse Sources {#checkout-clickhouse-sources}
``` bash ``` bash
$ git clone --recursive git@github.com:ClickHouse/ClickHouse.git # or https://github.com/ClickHouse/ClickHouse.git git clone --recursive git@github.com:ClickHouse/ClickHouse.git
# ...alternatively, you can use https://github.com/ClickHouse/ClickHouse.git as the repo URL.
``` ```
## Build ClickHouse {#build-clickhouse} ## Build ClickHouse {#build-clickhouse}
@ -46,37 +48,37 @@ $ git clone --recursive git@github.com:ClickHouse/ClickHouse.git # or https://gi
To build using Xcode's native AppleClang compiler: To build using Xcode's native AppleClang compiler:
``` bash ``` bash
$ cd ClickHouse cd ClickHouse
$ rm -rf build rm -rf build
$ mkdir build mkdir build
$ cd build cd build
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_JEMALLOC=OFF .. cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ cmake --build . --config RelWithDebInfo cmake --build . --config RelWithDebInfo
$ cd .. cd ..
``` ```
To build using Homebrew's vanilla Clang compiler: To build using Homebrew's vanilla Clang compiler:
``` bash ``` bash
$ cd ClickHouse cd ClickHouse
$ rm -rf build rm -rf build
$ mkdir build mkdir build
$ cd build cd build
$ cmake -DCMAKE_C_COMPILER=$(brew --prefix llvm)/bin/clang -DCMAKE_CXX_COMPILER==$(brew --prefix llvm)/bin/clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_JEMALLOC=OFF .. cmake -DCMAKE_C_COMPILER=$(brew --prefix llvm)/bin/clang -DCMAKE_CXX_COMPILER=$(brew --prefix llvm)/bin/clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ cmake --build . --config RelWithDebInfo cmake --build . --config RelWithDebInfo
$ cd .. cd ..
``` ```
To build using Homebrew's vanilla GCC compiler: To build using Homebrew's vanilla GCC compiler:
``` bash ``` bash
$ cd ClickHouse cd ClickHouse
$ rm -rf build rm -rf build
$ mkdir build mkdir build
$ cd build cd build
$ cmake -DCMAKE_C_COMPILER=$(brew --prefix gcc)/bin/gcc-10 -DCMAKE_CXX_COMPILER=$(brew --prefix gcc)/bin/g++-10 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_JEMALLOC=OFF .. cmake -DCMAKE_C_COMPILER=$(brew --prefix gcc)/bin/gcc-10 -DCMAKE_CXX_COMPILER=$(brew --prefix gcc)/bin/g++-10 -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ cmake --build . --config RelWithDebInfo cmake --build . --config RelWithDebInfo
$ cd .. cd ..
``` ```
## Caveats {#caveats} ## Caveats {#caveats}
@ -115,7 +117,7 @@ To do so, create the `/Library/LaunchDaemons/limit.maxfiles.plist` file with the
Execute the following command: Execute the following command:
``` bash ``` bash
$ sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist
``` ```
Reboot. Reboot.

View File

@ -94,10 +94,10 @@ postgres=# INSERT INTO test (int_id, str, "float") VALUES (1,'test',2);
INSERT 0 1 INSERT 0 1
postgresql> SELECT * FROM test; postgresql> SELECT * FROM test;
int_id | int_nullable | float | str | float_nullable int_id | int_nullable | float | str | float_nullable
--------+--------------+-------+------+---------------- --------+--------------+-------+------+----------------
1 | | 2 | test | 1 | | 2 | test |
(1 row) (1 row)
``` ```
Table in ClickHouse, retrieving data from the PostgreSQL table created above: Table in ClickHouse, retrieving data from the PostgreSQL table created above:

View File

@ -18,11 +18,17 @@ Engine parameters:
- `num_layers` Parallelism layer. Physically, the table will be represented as `num_layers` of independent buffers. Recommended value: 16. - `num_layers` Parallelism layer. Physically, the table will be represented as `num_layers` of independent buffers. Recommended value: 16.
- `min_time`, `max_time`, `min_rows`, `max_rows`, `min_bytes`, and `max_bytes` Conditions for flushing data from the buffer. - `min_time`, `max_time`, `min_rows`, `max_rows`, `min_bytes`, and `max_bytes` Conditions for flushing data from the buffer.
Optional engine parameters:
- `flush_time`, `flush_rows`, `flush_bytes` Conditions for flushing data from the buffer, that will happen only in background (ommited or zero means no `flush*` parameters).
Data is flushed from the buffer and written to the destination table if all the `min*` conditions or at least one `max*` condition are met. Data is flushed from the buffer and written to the destination table if all the `min*` conditions or at least one `max*` condition are met.
- `min_time`, `max_time` Condition for the time in seconds from the moment of the first write to the buffer. Also if at least one `flush*` condition are met flush initiated in background, this is different from `max*`, since `flush*` allows you to configure background flushes separately to avoid adding latency for `INSERT` (into `Buffer`) queries.
- `min_rows`, `max_rows` Condition for the number of rows in the buffer.
- `min_bytes`, `max_bytes` Condition for the number of bytes in the buffer. - `min_time`, `max_time`, `flush_time` Condition for the time in seconds from the moment of the first write to the buffer.
- `min_rows`, `max_rows`, `flush_rows` Condition for the number of rows in the buffer.
- `min_bytes`, `max_bytes`, `flush_bytes` Condition for the number of bytes in the buffer.
During the write operation, data is inserted to a `num_layers` number of random buffers. Or, if the data part to insert is large enough (greater than `max_rows` or `max_bytes`), it is written directly to the destination table, omitting the buffer. During the write operation, data is inserted to a `num_layers` number of random buffers. Or, if the data part to insert is large enough (greater than `max_rows` or `max_bytes`), it is written directly to the destination table, omitting the buffer.

View File

@ -58,8 +58,7 @@ ClickHouse artificially executes `INSERT` longer (adds sleep) so that the
## inactive_parts_to_throw_insert {#inactive-parts-to-throw-insert} ## inactive_parts_to_throw_insert {#inactive-parts-to-throw-insert}
If the number of inactive parts in a single partition more than the `inactive_parts_to_throw_insert` value, `INSERT` is interrupted with the `Too many inactive parts (N). Parts cleaning are processing significantly slower than inserts` exception. If the number of inactive parts in a single partition more than the `inactive_parts_to_throw_insert` value, `INSERT` is interrupted with the "Too many inactive parts (N). Parts cleaning are processing significantly slower than inserts" exception.
Possible values: Possible values:

View File

@ -1565,6 +1565,17 @@ Possible values:
Default value: 0 Default value: 0
## optimize_skip_unused_shards_rewrite_in {#optimize-skip-unused-shardslrewrite-in}
Rewrite IN in query for remote shards to exclude values that does not belong to the shard (requires optimize_skip_unused_shards).
Possible values:
- 0 — Disabled.
- 1 — Enabled.
Default value: 1 (since it requires `optimize_skip_unused_shards` anyway, which `0` by default)
## allow_nondeterministic_optimize_skip_unused_shards {#allow-nondeterministic-optimize-skip-unused-shards} ## allow_nondeterministic_optimize_skip_unused_shards {#allow-nondeterministic-optimize-skip-unused-shards}
Allow nondeterministic (like `rand` or `dictGet`, since later has some caveats with updates) functions in sharding key. Allow nondeterministic (like `rand` or `dictGet`, since later has some caveats with updates) functions in sharding key.

View File

@ -1213,6 +1213,62 @@ SELECT arrayFill(x -> not isNull(x), [1, null, 3, 11, 12, null, null, 5, 6, 14,
Note that the `arrayFill` is a [higher-order function](../../sql-reference/functions/index.md#higher-order-functions). You must pass a lambda function to it as the first argument, and it cant be omitted. Note that the `arrayFill` is a [higher-order function](../../sql-reference/functions/index.md#higher-order-functions). You must pass a lambda function to it as the first argument, and it cant be omitted.
## arrayFold(func, arr1, …, init) {#array-fold}
Returns an result of [folding](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) arrays and value `init` using function `func`.
I.e. result of calculation `func(arr1[n], …, func(arr1[n - 1], …, func(…, func(arr1[2], …, func(arr1[1], …, init)))))`.
Note that the `arrayMap` is a [higher-order function](../../sql-reference/functions/index.md#higher-order-functions). You must pass a lambda function to it as the first argument, and it cant be omitted.
**Arguments**
- `func` — The lambda function with `n+1` arguments (where `n` is number of input arrays), first `n` arguments are for
current elements of input arrays, and last argument is for current value of accumulator.
- `arr` — Any number of [arrays](../../sql-reference/data-types/array.md).
- `init` - Initial value of accumulator.
**Returned value**
Final value of accumulator.
**Examples**
The following example shows how to acquire product and sum of elements of array:
``` sql
SELECT arrayMap(x, accum -> (accum.1 * x, accum.2 + x), [1, 2, 3], (0, 1)) as res;
```
``` text
┌─res───────┐
│ (120, 15) │
└───────────┘
```
The following example shows how to reverse elements of array:
``` sql
SELECT arrayFold(x, acc -> arrayPushFront(acc, x), [1,2,3,4,5], emptyArrayUInt64()) as res;
```
``` text
┌─res─────────┐
│ [5,4,3,2,1] │
└─────────────┘
```
Folding may be used to access of already passed elements due to function calculation, for example:
``` sql
SELECT arrayFold(x, acc -> (x, concat(acc.2, toString(acc.1), ',')), [1,2], (0,''))
```
``` text
┌─res────────┐
│ (2,'0,1,') │
└────────────┘
```
## arrayReverseFill(func, arr1, …) {#array-reverse-fill} ## arrayReverseFill(func, arr1, …) {#array-reverse-fill}
Scan through `arr1` from the last element to the first element and replace `arr1[i]` by `arr1[i + 1]` if `func` returns 0. The last element of `arr1` will not be replaced. Scan through `arr1` from the last element to the first element and replace `arr1[i]` by `arr1[i + 1]` if `func` returns 0. The last element of `arr1` will not be replaced.

View File

@ -33,7 +33,7 @@ SELECT bitmapBuild([1, 2, 3, 4, 5]) AS res, toTypeName(res);
``` text ``` text
┌─res─┬─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─────┐ ┌─res─┬─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─────┐
 │ AggregateFunction(groupBitmap, UInt8) │ │ │ AggregateFunction(groupBitmap, UInt8)
└─────┴──────────────────────────────────────────────┘ └─────┴──────────────────────────────────────────────┘
``` ```

View File

@ -437,13 +437,13 @@ A [FixedString(16)](../../sql-reference/data-types/fixedstring.md) data type has
**Example** **Example**
``` sql ``` sql
SELECT murmurHash3_128('example_string') AS MurmurHash3, toTypeName(MurmurHash3) AS type; SELECT hex(murmurHash3_128('example_string')) AS MurmurHash3, toTypeName(MurmurHash3) AS type;
``` ```
``` text ``` text
┌─MurmurHash3──────┬─type────────────┐ ┌─MurmurHash3──────────────────────┬─type───┐
6<EFBFBD>1<1C>4"S5KT<4B>~~q │ FixedString(16) 368A1A311CB7342253354B548E7E7E71 │ String
└──────────────────┴─────────────────┘ └──────────────────────────────────┴────────┘
``` ```
## xxHash32, xxHash64 {#hash-functions-xxhash32} ## xxHash32, xxHash64 {#hash-functions-xxhash32}

View File

@ -16,7 +16,7 @@ The following operations with [partitions](../../../engines/table-engines/merget
- [CLEAR COLUMN IN PARTITION](#alter_clear-column-partition) — Resets the value of a specified column in a partition. - [CLEAR COLUMN IN PARTITION](#alter_clear-column-partition) — Resets the value of a specified column in a partition.
- [CLEAR INDEX IN PARTITION](#alter_clear-index-partition) — Resets the specified secondary index in a partition. - [CLEAR INDEX IN PARTITION](#alter_clear-index-partition) — Resets the specified secondary index in a partition.
- [FREEZE PARTITION](#alter_freeze-partition) — Creates a backup of a partition. - [FREEZE PARTITION](#alter_freeze-partition) — Creates a backup of a partition.
- [FETCH PARTITION](#alter_fetch-partition) — Downloads a partition from another server. - [FETCH PARTITION\|PART](#alter_fetch-partition) — Downloads a part or partition from another server.
- [MOVE PARTITION\|PART](#alter_move-partition) — Move partition/data part to another disk or volume. - [MOVE PARTITION\|PART](#alter_move-partition) — Move partition/data part to another disk or volume.
<!-- --> <!-- -->
@ -198,29 +198,35 @@ ALTER TABLE table_name CLEAR INDEX index_name IN PARTITION partition_expr
The query works similar to `CLEAR COLUMN`, but it resets an index instead of a column data. The query works similar to `CLEAR COLUMN`, but it resets an index instead of a column data.
## FETCH PARTITION {#alter_fetch-partition} ## FETCH PARTITION|PART {#alter_fetch-partition}
``` sql ``` sql
ALTER TABLE table_name FETCH PARTITION partition_expr FROM 'path-in-zookeeper' ALTER TABLE table_name FETCH PARTITION|PART partition_expr FROM 'path-in-zookeeper'
``` ```
Downloads a partition from another server. This query only works for the replicated tables. Downloads a partition from another server. This query only works for the replicated tables.
The query does the following: The query does the following:
1. Downloads the partition from the specified shard. In path-in-zookeeper you must specify a path to the shard in ZooKeeper. 1. Downloads the partition|part from the specified shard. In path-in-zookeeper you must specify a path to the shard in ZooKeeper.
2. Then the query puts the downloaded data to the `detached` directory of the `table_name` table. Use the [ATTACH PARTITION\|PART](#alter_attach-partition) query to add the data to the table. 2. Then the query puts the downloaded data to the `detached` directory of the `table_name` table. Use the [ATTACH PARTITION\|PART](#alter_attach-partition) query to add the data to the table.
For example: For example:
1. FETCH PARTITION
``` sql ``` sql
ALTER TABLE users FETCH PARTITION 201902 FROM '/clickhouse/tables/01-01/visits'; ALTER TABLE users FETCH PARTITION 201902 FROM '/clickhouse/tables/01-01/visits';
ALTER TABLE users ATTACH PARTITION 201902; ALTER TABLE users ATTACH PARTITION 201902;
``` ```
2. FETCH PART
``` sql
ALTER TABLE users FETCH PART 201901_2_2_0 FROM '/clickhouse/tables/01-01/visits';
ALTER TABLE users ATTACH PART 201901_2_2_0;
```
Note that: Note that:
- The `ALTER ... FETCH PARTITION` query isnt replicated. It places the partition to the `detached` directory only on the local server. - The `ALTER ... FETCH PARTITION|PART` query isnt replicated. It places the part or partition to the `detached` directory only on the local server.
- The `ALTER TABLE ... ATTACH` query is replicated. It adds the data to all replicas. The data is added to one of the replicas from the `detached` directory, and to the others - from neighboring replicas. - The `ALTER TABLE ... ATTACH` query is replicated. It adds the data to all replicas. The data is added to one of the replicas from the `detached` directory, and to the others - from neighboring replicas.
Before downloading, the system checks if the partition exists and the table structure matches. The most appropriate replica is selected automatically from the healthy replicas. Before downloading, the system checks if the partition exists and the table structure matches. The most appropriate replica is selected automatically from the healthy replicas.

View File

@ -5,39 +5,81 @@ toc_title: ROW POLICY
# CREATE ROW POLICY {#create-row-policy-statement} # CREATE ROW POLICY {#create-row-policy-statement}
Creates [filters for rows](../../../operations/access-rights.md#row-policy-management), which a user can read from a table. Creates a [row policy](../../../operations/access-rights.md#row-policy-management), i.e. a filter used to determine which rows a user can read from a table.
Syntax: Syntax:
``` sql ``` sql
CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name1 [ON CLUSTER cluster_name1] ON [db1.]table1 CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name1 [ON CLUSTER cluster_name1] ON [db1.]table1
[, policy_name2 [ON CLUSTER cluster_name2] ON [db2.]table2 ...] [, policy_name2 [ON CLUSTER cluster_name2] ON [db2.]table2 ...]
[FOR SELECT] USING condition
[AS {PERMISSIVE | RESTRICTIVE}] [AS {PERMISSIVE | RESTRICTIVE}]
[FOR SELECT]
[USING condition]
[TO {role1 [, role2 ...] | ALL | ALL EXCEPT role1 [, role2 ...]}] [TO {role1 [, role2 ...] | ALL | ALL EXCEPT role1 [, role2 ...]}]
``` ```
`ON CLUSTER` clause allows creating row policies on a cluster, see [Distributed DDL](../../../sql-reference/distributed-ddl.md). ## USING Clause {#create-row-policy-using}
## AS Clause {#create-row-policy-as} Allows to specify a condition to filter rows. An user will see a row if the condition is calculated to non-zero for the row.
Using this section you can create permissive or restrictive policies.
Permissive policy grants access to rows. Permissive policies which apply to the same table are combined together using the boolean `OR` operator. Policies are permissive by default.
Restrictive policy restricts access to rows. Restrictive policies which apply to the same table are combined together using the boolean `AND` operator.
Restrictive policies apply to rows that passed the permissive filters. If you set restrictive policies but no permissive policies, the user cant get any row from the table.
## TO Clause {#create-row-policy-to} ## TO Clause {#create-row-policy-to}
In the section `TO` you can provide a mixed list of roles and users, for example, `CREATE ROW POLICY ... TO accountant, john@localhost`. In the section `TO` you can provide a list of users and roles this policy should work for. For example, `CREATE ROW POLICY ... TO accountant, john@localhost`.
Keyword `ALL` means all the ClickHouse users including current user. Keywords `ALL EXCEPT` allow to exclude some users from the all users list, for example, `CREATE ROW POLICY ... TO ALL EXCEPT accountant, john@localhost` Keyword `ALL` means all the ClickHouse users including current user. Keyword `ALL EXCEPT` allow to exclude some users from the all users list, for example, `CREATE ROW POLICY ... TO ALL EXCEPT accountant, john@localhost`
## Examples {#examples} !!! note "Note"
If there are no row policies defined for a table then any user can `SELECT` all the row from the table. Defining one or more row policies for the table makes the access to the table depending on the row policies no matter if those row policies are defined for the current user or not. For example, the following policy
`CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter`
`CREATE ROW POLICY filter ON mydb.mytable FOR SELECT USING a<1000 TO accountant, john@localhost` forbids the users `mira` and `peter` to see the rows with `b != 1`, and any non-mentioned user (e.g., the user `paul`) will see no rows from `mydb.table1` at all.
If that's not desirable it can't be fixed by adding one more row policy, like the following:
`CREATE ROW POLICY filter ON mydb.mytable FOR SELECT USING a<1000 TO ALL EXCEPT mira` `CREATE ROW POLICY pol2 ON mydb.table1 USING 1 TO ALL EXCEPT mira, peter`
## AS Clause {#create-row-policy-as}
It's allowed to have more than one policy enabled on the same table for the same user at the one time. So we need a way to combine the conditions from multiple policies.
By default policies are combined using the boolean `OR` operator. For example, the following policies
``` sql
CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 TO peter, antonio
```
enables the user `peter` to see rows with either `b=1` or `c=2`.
The `AS` clause specifies how policies should be combined with other policies. Policies can be either permissive or restrictive. By default policies are permissive, which means they are combined using the boolean `OR` operator.
A policy can be defined as restrictive as an alternative. Restrictive policies are combined using the boolean `AND` operator.
Here is the general formula:
```
row_is_visible = (one or more of the permissive policies' conditions are non-zero) AND
(all of the restrictive policies's conditions are non-zero)
```
For example, the following policies
``` sql
CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 AS RESTRICTIVE TO peter, antonio
```
enables the user `peter` to see rows only if both `b=1` AND `c=2`.
## ON CLUSTER Clause {#create-row-policy-on-cluster}
Allows creating row policies on a cluster, see [Distributed DDL](../../../sql-reference/distributed-ddl.md).
## Examples
`CREATE ROW POLICY filter1 ON mydb.mytable USING a<1000 TO accountant, john@localhost`
`CREATE ROW POLICY filter2 ON mydb.mytable USING a<1000 AND b=5 TO ALL EXCEPT mira`
`CREATE ROW POLICY filter3 ON mydb.mytable USING 1 TO admin`

View File

@ -279,7 +279,7 @@ Allows executing [ALTER](../../sql-reference/statements/alter/index.md) queries
- `ALTER MATERIALIZE TTL`. Level: `TABLE`. Aliases: `MATERIALIZE TTL` - `ALTER MATERIALIZE TTL`. Level: `TABLE`. Aliases: `MATERIALIZE TTL`
- `ALTER SETTINGS`. Level: `TABLE`. Aliases: `ALTER SETTING`, `ALTER MODIFY SETTING`, `MODIFY SETTING` - `ALTER SETTINGS`. Level: `TABLE`. Aliases: `ALTER SETTING`, `ALTER MODIFY SETTING`, `MODIFY SETTING`
- `ALTER MOVE PARTITION`. Level: `TABLE`. Aliases: `ALTER MOVE PART`, `MOVE PARTITION`, `MOVE PART` - `ALTER MOVE PARTITION`. Level: `TABLE`. Aliases: `ALTER MOVE PART`, `MOVE PARTITION`, `MOVE PART`
- `ALTER FETCH PARTITION`. Level: `TABLE`. Aliases: `FETCH PARTITION` - `ALTER FETCH PARTITION`. Level: `TABLE`. Aliases: `ALTER FETCH PART`, `FETCH PARTITION`, `FETCH PART`
- `ALTER FREEZE PARTITION`. Level: `TABLE`. Aliases: `FREEZE PARTITION` - `ALTER FREEZE PARTITION`. Level: `TABLE`. Aliases: `FREEZE PARTITION`
- `ALTER VIEW` Level: `GROUP` - `ALTER VIEW` Level: `GROUP`
- `ALTER VIEW REFRESH`. Level: `VIEW`. Aliases: `ALTER LIVE VIEW REFRESH`, `REFRESH VIEW` - `ALTER VIEW REFRESH`. Level: `VIEW`. Aliases: `ALTER LIVE VIEW REFRESH`, `REFRESH VIEW`

View File

@ -65,9 +65,9 @@ postgres=# INSERT INTO test (int_id, str, "float") VALUES (1,'test',2);
INSERT 0 1 INSERT 0 1
postgresql> SELECT * FROM test; postgresql> SELECT * FROM test;
int_id | int_nullable | float | str | float_nullable int_id | int_nullable | float | str | float_nullable
--------+--------------+-------+------+---------------- --------+--------------+-------+------+----------------
1 | | 2 | test | 1 | | 2 | test |
(1 row) (1 row)
``` ```

View File

@ -35,7 +35,7 @@ SELECT bitmapBuild([1, 2, 3, 4, 5]) AS res, toTypeName(res)
``` text ``` text
┌─res─┬─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─────┐ ┌─res─┬─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─────┐
 │ AggregateFunction(groupBitmap, UInt8) │ │ │ AggregateFunction(groupBitmap, UInt8)
└─────┴──────────────────────────────────────────────┘ └─────┴──────────────────────────────────────────────┘
``` ```

View File

@ -434,13 +434,13 @@ A [FixedString(16)](../../sql-reference/data-types/fixedstring.md) データ型
**例** **例**
``` sql ``` sql
SELECT murmurHash3_128('example_string') AS MurmurHash3, toTypeName(MurmurHash3) AS type SELECT hex(murmurHash3_128('example_string')) AS MurmurHash3, toTypeName(MurmurHash3) AS type;
``` ```
``` text ``` text
┌─MurmurHash3──────┬─type────────────┐ ┌─MurmurHash3──────────────────────┬─type───┐
6<EFBFBD>1<1C>4"S5KT<4B>~~q │ FixedString(16) 368A1A311CB7342253354B548E7E7E71 │ String
└──────────────────┴─────────────────┘ └──────────────────────────────────┴────────┘
``` ```
## xxHash32,xxHash64 {#hash-functions-xxhash32} ## xxHash32,xxHash64 {#hash-functions-xxhash32}

View File

@ -22,7 +22,7 @@ CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
Структура таблицы может отличаться от исходной структуры таблицы PostgreSQL: Структура таблицы может отличаться от исходной структуры таблицы PostgreSQL:
- Имена столбцов должны быть такими же, как в исходной таблице MySQL, но вы можете использовать только некоторые из этих столбцов и в любом порядке. - Имена столбцов должны быть такими же, как в исходной таблице PostgreSQL, но вы можете использовать только некоторые из этих столбцов и в любом порядке.
- Типы столбцов могут отличаться от типов в исходной таблице PostgreSQL. ClickHouse пытается [приводить](../../../sql-reference/functions/type-conversion-functions.md#type_conversion_function-cast) values to the ClickHouse data types. - Типы столбцов могут отличаться от типов в исходной таблице PostgreSQL. ClickHouse пытается [приводить](../../../sql-reference/functions/type-conversion-functions.md#type_conversion_function-cast) values to the ClickHouse data types.
- Настройка `external_table_functions_use_nulls` определяет как обрабатывать Nullable столбцы. По умолчанию 1, если 0 - табличная функция не будет делать nullable столбцы и будет вместо null выставлять значения по умолчанию для скалярного типа. Это также применимо для null значений внутри массивов. - Настройка `external_table_functions_use_nulls` определяет как обрабатывать Nullable столбцы. По умолчанию 1, если 0 - табличная функция не будет делать nullable столбцы и будет вместо null выставлять значения по умолчанию для скалярного типа. Это также применимо для null значений внутри массивов.
@ -94,10 +94,10 @@ postgres=# INSERT INTO test (int_id, str, "float") VALUES (1,'test',2);
INSERT 0 1 INSERT 0 1
postgresql> SELECT * FROM test; postgresql> SELECT * FROM test;
int_id | int_nullable | float | str | float_nullable int_id | int_nullable | float | str | float_nullable
--------+--------------+-------+------+---------------- --------+--------------+-------+------+----------------
1 | | 2 | test | 1 | | 2 | test |
(1 row) (1 row)
``` ```
Таблица в ClickHouse, получение данных из PostgreSQL таблицы, созданной выше: Таблица в ClickHouse, получение данных из PostgreSQL таблицы, созданной выше:

View File

@ -55,6 +55,26 @@ Eсли число кусков в партиции превышает знач
ClickHouse искусственно выполняет `INSERT` дольше (добавляет sleep), чтобы фоновый механизм слияния успевал слиять куски быстрее, чем они добавляются. ClickHouse искусственно выполняет `INSERT` дольше (добавляет sleep), чтобы фоновый механизм слияния успевал слиять куски быстрее, чем они добавляются.
## inactive_parts_to_throw_insert {#inactive-parts-to-throw-insert}
Если число неактивных кусков в партиции превышает значение `inactive_parts_to_throw_insert`, `INSERT` прерывается с исключением «Too many inactive parts (N). Parts cleaning are processing significantly slower than inserts».
Возможные значения:
- Положительное целое число.
Значение по умолчанию: 0 (не ограничено).
## inactive_parts_to_delay_insert {#inactive-parts-to-delay-insert}
Если число неактивных кусков в партиции больше или равно значению `inactive_parts_to_delay_insert`, `INSERT` искусственно замедляется. Это полезно, когда сервер не может быстро очистить неактивные куски.
Возможные значения:
- Положительное целое число.
Значение по умолчанию: 0 (не ограничено).
## max_delay_to_insert {#max-delay-to-insert} ## max_delay_to_insert {#max-delay-to-insert}
Величина в секундах, которая используется для расчета задержки `INSERT`, если число кусков в партиции превышает значение [parts_to_delay_insert](#parts-to-delay-insert). Величина в секундах, которая используется для расчета задержки `INSERT`, если число кусков в партиции превышает значение [parts_to_delay_insert](#parts-to-delay-insert).

View File

@ -15,10 +15,12 @@
- [`groupBitOr`](../../sql-reference/aggregate-functions/reference/groupbitor.md#groupbitor) - [`groupBitOr`](../../sql-reference/aggregate-functions/reference/groupbitor.md#groupbitor)
- [`groupBitXor`](../../sql-reference/aggregate-functions/reference/groupbitxor.md#groupbitxor) - [`groupBitXor`](../../sql-reference/aggregate-functions/reference/groupbitxor.md#groupbitxor)
- [`groupArrayArray`](../../sql-reference/aggregate-functions/reference/grouparray.md#agg_function-grouparray) - [`groupArrayArray`](../../sql-reference/aggregate-functions/reference/grouparray.md#agg_function-grouparray)
- [`groupUniqArrayArray`](../../sql-reference/aggregate-functions/reference/groupuniqarray.md#groupuniqarray) - [`groupUniqArrayArray`](../../sql-reference/aggregate-functions/reference/groupuniqarray.md)
- [`sumMap`](../../sql-reference/aggregate-functions/reference/summap.md#agg_functions-summap) - [`sumMap`](../../sql-reference/aggregate-functions/reference/summap.md#agg_functions-summap)
- [`minMap`](../../sql-reference/aggregate-functions/reference/minmap.md#agg_functions-minmap) - [`minMap`](../../sql-reference/aggregate-functions/reference/minmap.md#agg_functions-minmap)
- [`maxMap`](../../sql-reference/aggregate-functions/reference/maxmap.md#agg_functions-maxmap) - [`maxMap`](../../sql-reference/aggregate-functions/reference/maxmap.md#agg_functions-maxmap)
- [`argMin`](../../sql-reference/aggregate-functions/reference/argmin.md)
- [`argMax`](../../sql-reference/aggregate-functions/reference/argmax.md)
!!! note "Примечание" !!! note "Примечание"
Значения `SimpleAggregateFunction(func, Type)` отображаются и хранятся так же, как и `Type`, поэтому комбинаторы [-Merge](../../sql-reference/aggregate-functions/combinators.md#aggregate_functions_combinators-merge) и [-State](../../sql-reference/aggregate-functions/combinators.md#agg-functions-combinator-state) не требуются. Значения `SimpleAggregateFunction(func, Type)` отображаются и хранятся так же, как и `Type`, поэтому комбинаторы [-Merge](../../sql-reference/aggregate-functions/combinators.md#aggregate_functions_combinators-merge) и [-State](../../sql-reference/aggregate-functions/combinators.md#agg-functions-combinator-state) не требуются.

View File

@ -1147,6 +1147,62 @@ SELECT arrayReverseFill(x -> not isNull(x), [1, null, 3, 11, 12, null, null, 5,
Функция `arrayReverseFill` является [функцией высшего порядка](../../sql-reference/functions/index.md#higher-order-functions) — в качестве первого аргумента ей нужно передать лямбда-функцию, и этот аргумент не может быть опущен. Функция `arrayReverseFill` является [функцией высшего порядка](../../sql-reference/functions/index.md#higher-order-functions) — в качестве первого аргумента ей нужно передать лямбда-функцию, и этот аргумент не может быть опущен.
## arrayFold(func, arr1, …, init) {#array-fold}
Возвращает результат [сворачивания](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%91%D1%80%D1%82%D0%BA%D0%B0_%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0) массивов и начального значения `init` с помощью функции `func`.
Т.е. результат вычисления `func(arr1[n], …, func(arr1[n - 1], …, func(…, func(arr1[2], …, func(arr1[1], …, init)))))`.
Функция `arrayFold` является [функцией высшего порядка](../../sql-reference/functions/index.md#higher-order-functions) — в качестве первого аргумента ей нужно передать лямбда-функцию, и этот аргумент не может быть опущен.
**Аргументы**
- `func` — лямбда-функция с `n+1` параметром (где `n` это количество входных массивов), причём первые `n` параметров
используются для текущих элементов входных массивов, а последний элемент для текущего значения аккумулятора.
- `arr` — произвольное количество [массивов](../../sql-reference/data-types/array.md).
- `init` - начальное значение аккумулятора.
**Возвращаемое значение**
Итоговое значение аккумулятора.
**Примеры**
Следующий пример показывает, как вычислить произведение и сумму элементов массива:
``` sql
SELECT arrayMap(x, accum -> (accum.1 * x, accum.2 + x), [1, 2, 3], (0, 1)) as res;
```
``` text
┌─res───────┐
│ (120, 15) │
└───────────┘
```
В этом примере показано, как обратить массив:
``` sql
SELECT arrayFold(x, acc -> arrayPushFront(acc, x), [1,2,3,4,5], emptyArrayUInt64()) as res;
```
``` text
┌─res─────────┐
│ [5,4,3,2,1] │
└─────────────┘
```
Свёртка может быть использована для доступа к уже пройденным в процессе вычисления элементам. Например:
``` sql
SELECT arrayFold(x, acc -> (x, concat(acc.2, toString(acc.1), ',')), [1,2], (0,''))
```
``` text
┌─res────────┐
│ (2,'0,1,') │
└────────────┘
```
## arraySplit(func, arr1, …) {#array-split} ## arraySplit(func, arr1, …) {#array-split}
Разделяет массив `arr1` на несколько. Если `func` возвращает не 0, то массив разделяется, а элемент помещается в левую часть. Массив не разбивается по первому элементу. Разделяет массив `arr1` на несколько. Если `func` возвращает не 0, то массив разделяется, а элемент помещается в левую часть. Массив не разбивается по первому элементу.
@ -1183,6 +1239,7 @@ SELECT arrayReverseSplit((x, y) -> y, [1, 2, 3, 4, 5], [1, 0, 0, 1, 0]) AS res
Функция `arrayReverseSplit` является [функцией высшего порядка](../../sql-reference/functions/index.md#higher-order-functions) — в качестве первого аргумента ей нужно передать лямбда-функцию, и этот аргумент не может быть опущен. Функция `arrayReverseSplit` является [функцией высшего порядка](../../sql-reference/functions/index.md#higher-order-functions) — в качестве первого аргумента ей нужно передать лямбда-функцию, и этот аргумент не может быть опущен.
## arrayExists(\[func,\] arr1, …) {#arrayexistsfunc-arr1} ## arrayExists(\[func,\] arr1, …) {#arrayexistsfunc-arr1}
Возвращает 1, если существует хотя бы один элемент массива `arr`, для которого функция func возвращает не 0. Иначе возвращает 0. Возвращает 1, если существует хотя бы один элемент массива `arr`, для которого функция func возвращает не 0. Иначе возвращает 0.

View File

@ -25,7 +25,7 @@ SELECT bitmapBuild([1, 2, 3, 4, 5]) AS res, toTypeName(res);
``` text ``` text
┌─res─┬─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─────┐ ┌─res─┬─toTypeName(bitmapBuild([1, 2, 3, 4, 5]))─────┐
 │ AggregateFunction(groupBitmap, UInt8) │ │ │ AggregateFunction(groupBitmap, UInt8)
└─────┴──────────────────────────────────────────────┘ └─────┴──────────────────────────────────────────────┘
``` ```

View File

@ -430,7 +430,7 @@ murmurHash3_128( expr )
**Аргументы** **Аргументы**
- `expr` — [выражение](../syntax.md#syntax-expressions), возвращающее значение типа[String](../../sql-reference/functions/hash-functions.md). - `expr` — [выражение](../syntax.md#syntax-expressions), возвращающее значение типа [String](../../sql-reference/functions/hash-functions.md).
**Возвращаемое значение** **Возвращаемое значение**
@ -439,13 +439,13 @@ murmurHash3_128( expr )
**Пример** **Пример**
``` sql ``` sql
SELECT murmurHash3_128('example_string') AS MurmurHash3, toTypeName(MurmurHash3) AS type; SELECT hex(murmurHash3_128('example_string')) AS MurmurHash3, toTypeName(MurmurHash3) AS type;
``` ```
``` text ``` text
┌─MurmurHash3──────┬─type────────────┐ ┌─MurmurHash3──────────────────────┬─type───┐
6<EFBFBD>1<1C>4"S5KT<4B>~~q │ FixedString(16) 368A1A311CB7342253354B548E7E7E71 │ String
└──────────────────┴─────────────────┘ └──────────────────────────────────┴────────┘
``` ```
## xxHash32, xxHash64 {#hash-functions-xxhash32-xxhash64} ## xxHash32, xxHash64 {#hash-functions-xxhash32-xxhash64}

View File

@ -5,7 +5,7 @@ toc_title: "Политика доступа"
# CREATE ROW POLICY {#create-row-policy-statement} # CREATE ROW POLICY {#create-row-policy-statement}
Создает [фильтры для строк](../../../operations/access-rights.md#row-policy-management), которые пользователь может прочесть из таблицы. Создает [политики доступа к строкам](../../../operations/access-rights.md#row-policy-management), т.е. фильтры, которые определяют, какие строки пользователь может читать из таблицы.
Синтаксис: Синтаксис:
@ -13,33 +13,74 @@ toc_title: "Политика доступа"
CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name1 [ON CLUSTER cluster_name1] ON [db1.]table1 CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name1 [ON CLUSTER cluster_name1] ON [db1.]table1
[, policy_name2 [ON CLUSTER cluster_name2] ON [db2.]table2 ...] [, policy_name2 [ON CLUSTER cluster_name2] ON [db2.]table2 ...]
[AS {PERMISSIVE | RESTRICTIVE}] [AS {PERMISSIVE | RESTRICTIVE}]
[FOR SELECT] [FOR SELECT] USING condition
[USING condition]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}] [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
``` ```
Секция `ON CLUSTER` позволяет создавать фильтры для строк на кластере, см. [Распределенные DDL запросы](../../../sql-reference/distributed-ddl.md). ## Секция USING {#create-row-policy-using}
## Секция AS {#create-row-policy-as} Секция `USING` указывает условие для фильтрации строк. Пользователь может видеть строку, если это условие, вычисленное для строки, дает ненулевой результат.
С помощью данной секции можно создать политику разрешения или ограничения.
Политика разрешения предоставляет доступ к строкам. Разрешительные политики, которые применяются к одной таблице, объединяются с помощью логического оператора `OR`. Политики являются разрешительными по умолчанию.
Политика ограничения запрещает доступ к строкам. Ограничительные политики, которые применяются к одной таблице, объединяются логическим оператором `AND`.
Ограничительные политики применяются к строкам, прошедшим фильтр разрешительной политики. Если вы не зададите разрешительные политики, пользователь не сможет обращаться ни к каким строкам из таблицы.
## Секция TO {#create-row-policy-to} ## Секция TO {#create-row-policy-to}
В секции `TO` вы можете перечислить как роли, так и пользователей. Например, `CREATE ROW POLICY ... TO accountant, john@localhost`. В секции `TO` перечисляются пользователи и роли, для которых должна действовать политика. Например, `CREATE ROW POLICY ... TO accountant, john@localhost`.
Ключевым словом `ALL` обозначаются все пользователи, включая текущего. Ключевые слова `ALL EXCEPT` позволяют исключить пользователей из списка всех пользователей. Например, `CREATE ROW POLICY ... TO ALL EXCEPT accountant, john@localhost` Ключевым словом `ALL` обозначаются все пользователи, включая текущего. Ключевые слова `ALL EXCEPT` позволяют исключить пользователей из списка всех пользователей. Например, `CREATE ROW POLICY ... TO ALL EXCEPT accountant, john@localhost`
!!! note "Note"
Если для таблицы не задано ни одной политики доступа к строкам, то любой пользователь может выполнить команду SELECT и получить все строки таблицы. Если определить хотя бы одну политику для таблицы, до доступ к строкам будет управляться этими политиками, причем для всех пользователей (даже для тех, для кого политики не определялись). Например, следующая политика
`CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter`
запретит пользователям `mira` и `peter` видеть строки с `b != 1`, и еще запретит всем остальным пользователям (например, пользователю `paul`) видеть какие-либо строки вообще из таблицы `mydb.table1`.
Если это нежелательно, такое поведение можно исправить, определив дополнительную политику:
`CREATE ROW POLICY pol2 ON mydb.table1 USING 1 TO ALL EXCEPT mira, peter`
## Секция AS {#create-row-policy-as}
Может быть одновременно активно более одной политики для одной и той же таблицы и одного и того же пользователя. Поэтому нам нужен способ комбинировать политики.
По умолчанию политики комбинируются с использованием логического оператора `OR`. Например, политики:
``` sql
CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 TO peter, antonio
```
разрешат пользователю с именем `peter` видеть строки, для которых будет верно `b=1` или `c=2`.
Секция `AS` указывает, как политики должны комбинироваться с другими политиками. Политики могут быть или разрешительными (`PERMISSIVE`), или ограничительными (`RESTRICTIVE`). По умолчанию политики создаются разрешительными (`PERMISSIVE`); такие политики комбинируются с использованием логического оператора `OR`.
Ограничительные (`RESTRICTIVE`) политики комбинируются с использованием логического оператора `AND`.
Общая формула выглядит так:
```
строка_видима = (одна или больше permissive-политик дала ненулевой результат проверки условия) И
(все restrictive-политики дали ненулевой результат проверки условия)
```
Например, политики
``` sql
CREATE ROW POLICY pol1 ON mydb.table1 USING b=1 TO mira, peter
CREATE ROW POLICY pol2 ON mydb.table1 USING c=2 AS RESTRICTIVE TO peter, antonio
```
разрешат пользователю с именем `peter` видеть только те строки, для которых будет одновременно `b=1` и `c=2`.
## Секция ON CLUSTER {#create-row-policy-on-cluster}
Секция `ON CLUSTER` позволяет создавать политики на кластере, см. [Распределенные DDL запросы](../../../sql-reference/distributed-ddl.md).
## Примеры ## Примеры
`CREATE ROW POLICY filter ON mydb.mytable FOR SELECT USING a<1000 TO accountant, john@localhost` `CREATE ROW POLICY filter1 ON mydb.mytable USING a<1000 TO accountant, john@localhost`
`CREATE ROW POLICY filter ON mydb.mytable FOR SELECT USING a<1000 TO ALL EXCEPT mira` `CREATE ROW POLICY filter2 ON mydb.mytable USING a<1000 AND b=5 TO ALL EXCEPT mira`
`CREATE ROW POLICY filter3 ON mydb.mytable USING 1 TO admin`
<!--hide--> <!--hide-->

View File

@ -65,10 +65,10 @@ postgres=# INSERT INTO test (int_id, str, "float") VALUES (1,'test',2);
INSERT 0 1 INSERT 0 1
postgresql> SELECT * FROM test; postgresql> SELECT * FROM test;
int_id | int_nullable | float | str | float_nullable int_id | int_nullable | float | str | float_nullable
--------+--------------+-------+------+---------------- --------+--------------+-------+------+----------------
1 | | 2 | test | 1 | | 2 | test |
(1 row) (1 row)
``` ```
Получение данных в ClickHouse: Получение данных в ClickHouse:

View File

@ -109,7 +109,8 @@ def build_single_page_version(lang, args, nav, cfg):
extra['single_page'] = True extra['single_page'] = True
extra['is_amp'] = False extra['is_amp'] = False
with open(os.path.join(args.docs_dir, lang, 'single.md'), 'w') as single_md: single_md_path = os.path.join(args.docs_dir, lang, 'single.md')
with open(single_md_path, 'w') as single_md:
concatenate(lang, args.docs_dir, single_md, nav) concatenate(lang, args.docs_dir, single_md, nav)
with util.temp_dir() as site_temp: with util.temp_dir() as site_temp:
@ -221,3 +222,7 @@ def build_single_page_version(lang, args, nav, cfg):
subprocess.check_call(' '.join(create_pdf_command), shell=True) subprocess.check_call(' '.join(create_pdf_command), shell=True)
logging.info(f'Finished building single page version for {lang}') logging.info(f'Finished building single page version for {lang}')
if os.path.exists(single_md_path):
os.unlink(single_md_path)

View File

@ -108,14 +108,6 @@ void Suggest::loadImpl(Connection & connection, const ConnectionTimeouts & timeo
" UNION ALL " " UNION ALL "
"SELECT cluster FROM system.clusters" "SELECT cluster FROM system.clusters"
" UNION ALL " " UNION ALL "
"SELECT name FROM system.errors"
" UNION ALL "
"SELECT event FROM system.events"
" UNION ALL "
"SELECT metric FROM system.asynchronous_metrics"
" UNION ALL "
"SELECT metric FROM system.metrics"
" UNION ALL "
"SELECT macro FROM system.macros" "SELECT macro FROM system.macros"
" UNION ALL " " UNION ALL "
"SELECT policy_name FROM system.storage_policies" "SELECT policy_name FROM system.storage_policies"
@ -139,17 +131,12 @@ void Suggest::loadImpl(Connection & connection, const ConnectionTimeouts & timeo
query << ") WHERE notEmpty(res)"; query << ") WHERE notEmpty(res)";
Settings settings; fetch(connection, timeouts, query.str());
/// To show all rows from:
/// - system.errors
/// - system.events
settings.system_events_show_zero_values = true;
fetch(connection, timeouts, query.str(), settings);
} }
void Suggest::fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query, Settings & settings) void Suggest::fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query)
{ {
connection.sendQuery(timeouts, query, "" /* query_id */, QueryProcessingStage::Complete, &settings); connection.sendQuery(timeouts, query, "" /* query_id */, QueryProcessingStage::Complete);
while (true) while (true)
{ {

View File

@ -33,7 +33,7 @@ public:
private: private:
void loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit); void loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit);
void fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query, Settings & settings); void fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query);
void fillWordsFromBlock(const Block & block); void fillWordsFromBlock(const Block & block);
/// Words are fetched asynchronously. /// Words are fetched asynchronously.

View File

@ -222,8 +222,8 @@ Names extractPrimaryKeyColumnNames(const ASTPtr & storage_ast)
{ {
String pk_column = primary_key_expr_list->children[i]->getColumnName(); String pk_column = primary_key_expr_list->children[i]->getColumnName();
if (pk_column != sorting_key_column) if (pk_column != sorting_key_column)
throw Exception("Primary key must be a prefix of the sorting key, but in position " throw Exception("Primary key must be a prefix of the sorting key, but the column in the position "
+ toString(i) + " its column is " + pk_column + ", not " + sorting_key_column, + toString(i) + " is " + sorting_key_column +", not " + pk_column,
ErrorCodes::BAD_ARGUMENTS); ErrorCodes::BAD_ARGUMENTS);
if (!primary_key_columns_set.emplace(pk_column).second) if (!primary_key_columns_set.emplace(pk_column).second)

View File

@ -71,6 +71,9 @@ namespace ErrorCodes
} }
/// ANSI escape sequence for intense color in terminal.
#define HILITE "\033[1m"
#define END_HILITE "\033[0m"
using namespace DB; using namespace DB;
namespace po = boost::program_options; namespace po = boost::program_options;
@ -559,20 +562,32 @@ int mainEntryClickHouseInstall(int argc, char ** argv)
bool stdin_is_a_tty = isatty(STDIN_FILENO); bool stdin_is_a_tty = isatty(STDIN_FILENO);
bool stdout_is_a_tty = isatty(STDOUT_FILENO); bool stdout_is_a_tty = isatty(STDOUT_FILENO);
bool is_interactive = stdin_is_a_tty && stdout_is_a_tty;
/// dpkg or apt installers can ask for non-interactive work explicitly.
const char * debian_frontend_var = getenv("DEBIAN_FRONTEND");
bool noninteractive = debian_frontend_var && debian_frontend_var == std::string_view("noninteractive");
bool is_interactive = !noninteractive && stdin_is_a_tty && stdout_is_a_tty;
/// We can ask password even if stdin is closed/redirected but /dev/tty is available.
bool can_ask_password = !noninteractive && stdout_is_a_tty;
if (has_password_for_default_user) if (has_password_for_default_user)
{ {
fmt::print("Password for default user is already specified. To remind or reset, see {} and {}.\n", fmt::print(HILITE "Password for default user is already specified. To remind or reset, see {} and {}." END_HILITE "\n",
users_config_file.string(), users_d.string()); users_config_file.string(), users_d.string());
} }
else if (!is_interactive) else if (!can_ask_password)
{ {
fmt::print("Password for default user is empty string. See {} and {} to change it.\n", fmt::print(HILITE "Password for default user is empty string. See {} and {} to change it." END_HILITE "\n",
users_config_file.string(), users_d.string()); users_config_file.string(), users_d.string());
} }
else else
{ {
/// NOTE: When installing debian package with dpkg -i, stdin is not a terminal but we are still being able to enter password.
/// More sophisticated method with /dev/tty is used inside the `readpassphrase` function.
char buf[1000] = {}; char buf[1000] = {};
std::string password; std::string password;
if (auto * result = readpassphrase("Enter password for default user: ", buf, sizeof(buf), 0)) if (auto * result = readpassphrase("Enter password for default user: ", buf, sizeof(buf), 0))
@ -600,7 +615,7 @@ int mainEntryClickHouseInstall(int argc, char ** argv)
"</yandex>\n"; "</yandex>\n";
out.sync(); out.sync();
out.finalize(); out.finalize();
fmt::print("Password for default user is saved in file {}.\n", password_file); fmt::print(HILITE "Password for default user is saved in file {}." END_HILITE "\n", password_file);
#else #else
out << "<yandex>\n" out << "<yandex>\n"
" <users>\n" " <users>\n"
@ -611,12 +626,12 @@ int mainEntryClickHouseInstall(int argc, char ** argv)
"</yandex>\n"; "</yandex>\n";
out.sync(); out.sync();
out.finalize(); out.finalize();
fmt::print("Password for default user is saved in plaintext in file {}.\n", password_file); fmt::print(HILITE "Password for default user is saved in plaintext in file {}." END_HILITE "\n", password_file);
#endif #endif
has_password_for_default_user = true; has_password_for_default_user = true;
} }
else else
fmt::print("Password for default user is empty string. See {} and {} to change it.\n", fmt::print(HILITE "Password for default user is empty string. See {} and {} to change it." END_HILITE "\n",
users_config_file.string(), users_d.string()); users_config_file.string(), users_d.string());
} }
@ -641,7 +656,6 @@ int mainEntryClickHouseInstall(int argc, char ** argv)
" This is optional. Taskstats accounting will be disabled." " This is optional. Taskstats accounting will be disabled."
" To enable taskstats accounting you may add the required capability later manually.\"", " To enable taskstats accounting you may add the required capability later manually.\"",
"/tmp/test_setcap.sh", fs::canonical(main_bin_path).string()); "/tmp/test_setcap.sh", fs::canonical(main_bin_path).string());
fmt::print(" {}\n", command);
executeScript(command); executeScript(command);
#endif #endif

View File

@ -1,6 +1,6 @@
set (CLICKHOUSE_LIBRARY_BRIDGE_SOURCES set (CLICKHOUSE_LIBRARY_BRIDGE_SOURCES
library-bridge.cpp library-bridge.cpp
library-log.cpp LibraryInterface.cpp
LibraryBridge.cpp LibraryBridge.cpp
Handlers.cpp Handlers.cpp
HandlerFactory.cpp HandlerFactory.cpp
@ -17,7 +17,6 @@ add_executable(clickhouse-library-bridge ${CLICKHOUSE_LIBRARY_BRIDGE_SOURCES})
target_link_libraries(clickhouse-library-bridge PRIVATE target_link_libraries(clickhouse-library-bridge PRIVATE
daemon daemon
dbms dbms
clickhouse_parsers
bridge bridge
) )

View File

@ -1,4 +1,5 @@
#include "LibraryDictionarySourceExternal.h" #include "LibraryInterface.h"
#include <common/logger_useful.h> #include <common/logger_useful.h>
namespace namespace

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include <Common/StringUtils/StringUtils.h> #include <Common/StringUtils/StringUtils.h>
#include <Dictionaries/LibraryDictionarySourceExternal.h>
#include <Core/Block.h> #include <Core/Block.h>
#include <ext/bit_cast.h> #include <ext/bit_cast.h>
#include <ext/range.h> #include <ext/range.h>
#include "LibraryInterface.h"
namespace DB namespace DB
{ {

View File

@ -1,66 +0,0 @@
#include <Dictionaries/LibraryDictionarySourceExternal.h>
#include <common/logger_useful.h>
namespace
{
const char DICT_LOGGER_NAME[] = "LibraryDictionarySourceExternal";
}
namespace ClickHouseLibrary
{
std::string_view LIBRARY_CREATE_NEW_FUNC_NAME = "ClickHouseDictionary_v3_libNew";
std::string_view LIBRARY_CLONE_FUNC_NAME = "ClickHouseDictionary_v3_libClone";
std::string_view LIBRARY_DELETE_FUNC_NAME = "ClickHouseDictionary_v3_libDelete";
std::string_view LIBRARY_DATA_NEW_FUNC_NAME = "ClickHouseDictionary_v3_dataNew";
std::string_view LIBRARY_DATA_DELETE_FUNC_NAME = "ClickHouseDictionary_v3_dataDelete";
std::string_view LIBRARY_LOAD_ALL_FUNC_NAME = "ClickHouseDictionary_v3_loadAll";
std::string_view LIBRARY_LOAD_IDS_FUNC_NAME = "ClickHouseDictionary_v3_loadIds";
std::string_view LIBRARY_LOAD_KEYS_FUNC_NAME = "ClickHouseDictionary_v3_loadKeys";
std::string_view LIBRARY_IS_MODIFIED_FUNC_NAME = "ClickHouseDictionary_v3_isModified";
std::string_view LIBRARY_SUPPORTS_SELECTIVE_LOAD_FUNC_NAME = "ClickHouseDictionary_v3_supportsSelectiveLoad";
void log(LogLevel level, CString msg)
{
auto & logger = Poco::Logger::get(DICT_LOGGER_NAME);
switch (level)
{
case LogLevel::TRACE:
if (logger.trace())
logger.trace(msg);
break;
case LogLevel::DEBUG:
if (logger.debug())
logger.debug(msg);
break;
case LogLevel::INFORMATION:
if (logger.information())
logger.information(msg);
break;
case LogLevel::NOTICE:
if (logger.notice())
logger.notice(msg);
break;
case LogLevel::WARNING:
if (logger.warning())
logger.warning(msg);
break;
case LogLevel::ERROR:
if (logger.error())
logger.error(msg);
break;
case LogLevel::CRITICAL:
if (logger.critical())
logger.critical(msg);
break;
case LogLevel::FATAL:
if (logger.fatal())
logger.fatal(msg);
break;
}
}
}

View File

@ -26,11 +26,12 @@ target_link_libraries(clickhouse-odbc-bridge PRIVATE
dbms dbms
bridge bridge
clickhouse_parsers clickhouse_parsers
Poco::Data nanodbc
Poco::Data::ODBC unixodbc
) )
set_target_properties(clickhouse-odbc-bridge PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..) set_target_properties(clickhouse-odbc-bridge PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..)
target_compile_options (clickhouse-odbc-bridge PRIVATE -Wno-reserved-id-macro -Wno-keyword-macro)
if (USE_GDB_ADD_INDEX) if (USE_GDB_ADD_INDEX)
add_custom_command(TARGET clickhouse-odbc-bridge POST_BUILD COMMAND ${GDB_ADD_INDEX_EXE} ../clickhouse-odbc-bridge COMMENT "Adding .gdb-index to clickhouse-odbc-bridge" VERBATIM) add_custom_command(TARGET clickhouse-odbc-bridge POST_BUILD COMMAND ${GDB_ADD_INDEX_EXE} ../clickhouse-odbc-bridge COMMENT "Adding .gdb-index to clickhouse-odbc-bridge" VERBATIM)

View File

@ -2,29 +2,36 @@
#if USE_ODBC #if USE_ODBC
# include <DataTypes/DataTypeFactory.h> #include <DataTypes/DataTypeFactory.h>
# include <DataTypes/DataTypeNullable.h> #include <DataTypes/DataTypeNullable.h>
# include <Server/HTTP/WriteBufferFromHTTPServerResponse.h> #include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
# include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
# include <Parsers/ParserQueryWithOutput.h> #include <Parsers/ParserQueryWithOutput.h>
# include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>
# include <Poco/Data/ODBC/ODBCException.h> #include <Server/HTTP/HTMLForm.h>
# include <Poco/Data/ODBC/SessionImpl.h> #include <Poco/Net/HTTPServerRequest.h>
# include <Poco/Data/ODBC/Utility.h> #include <Poco/Net/HTTPServerResponse.h>
# include <Server/HTTP/HTMLForm.h> #include <Poco/NumberParser.h>
# include <Poco/Net/HTTPServerRequest.h> #include <common/logger_useful.h>
# include <Poco/Net/HTTPServerResponse.h> #include <Common/quoteString.h>
# include <Poco/NumberParser.h> #include <ext/scope_guard.h>
# include <common/logger_useful.h> #include "getIdentifierQuote.h"
# include <Common/quoteString.h> #include "validateODBCConnectionString.h"
# include <ext/scope_guard.h> #include "ODBCConnectionFactory.h"
# include "getIdentifierQuote.h"
# include "validateODBCConnectionString.h" #include <sql.h>
#include <sqlext.h>
# define POCO_SQL_ODBC_CLASS Poco::Data::ODBC
namespace DB namespace DB
{ {
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
extern const int BAD_ARGUMENTS;
}
namespace namespace
{ {
DataTypePtr getDataType(SQLSMALLINT type) DataTypePtr getDataType(SQLSMALLINT type)
@ -59,6 +66,7 @@ namespace
} }
} }
void ODBCColumnsInfoHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) void ODBCColumnsInfoHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
{ {
HTMLForm params(request, request.getStream()); HTMLForm params(request, request.getStream());
@ -77,88 +85,79 @@ void ODBCColumnsInfoHandler::handleRequest(HTTPServerRequest & request, HTTPServ
process_error("No 'table' param in request URL"); process_error("No 'table' param in request URL");
return; return;
} }
if (!params.has("connection_string")) if (!params.has("connection_string"))
{ {
process_error("No 'connection_string' in request URL"); process_error("No 'connection_string' in request URL");
return; return;
} }
std::string schema_name; std::string schema_name;
std::string table_name = params.get("table"); std::string table_name = params.get("table");
std::string connection_string = params.get("connection_string"); std::string connection_string = params.get("connection_string");
if (params.has("schema")) if (params.has("schema"))
{
schema_name = params.get("schema"); schema_name = params.get("schema");
LOG_TRACE(log, "Will fetch info for table '{}'", schema_name + "." + table_name);
}
else
LOG_TRACE(log, "Will fetch info for table '{}'", table_name);
LOG_TRACE(log, "Got connection str '{}'", connection_string); LOG_TRACE(log, "Got connection str '{}'", connection_string);
try try
{ {
const bool external_table_functions_use_nulls = Poco::NumberParser::parseBool(params.get("external_table_functions_use_nulls", "false")); const bool external_table_functions_use_nulls = Poco::NumberParser::parseBool(params.get("external_table_functions_use_nulls", "false"));
POCO_SQL_ODBC_CLASS::SessionImpl session(validateODBCConnectionString(connection_string), DBMS_DEFAULT_CONNECT_TIMEOUT_SEC); auto connection = ODBCConnectionFactory::instance().get(
SQLHDBC hdbc = session.dbc().handle(); validateODBCConnectionString(connection_string),
getContext()->getSettingsRef().odbc_bridge_connection_pool_size);
SQLHSTMT hstmt = nullptr; nanodbc::catalog catalog(*connection);
std::string catalog_name;
if (POCO_SQL_ODBC_CLASS::Utility::isError(SQLAllocStmt(hdbc, &hstmt))) /// In XDBC tables it is allowed to pass either database_name or schema_name in table definion, but not both of them.
throw POCO_SQL_ODBC_CLASS::ODBCException("Could not allocate connection handle."); /// They both are passed as 'schema' parameter in request URL, so it is not clear whether it is database_name or schema_name passed.
/// If it is schema_name then we know that database is added in odbc.ini. But if we have database_name as 'schema',
SCOPE_EXIT(SQLFreeStmt(hstmt, SQL_DROP)); /// it is not guaranteed. For nanodbc database_name must be either in odbc.ini or passed as catalog_name.
auto get_columns = [&]()
const auto & context_settings = getContext()->getSettingsRef();
/// TODO Why not do SQLColumns instead?
std::string name = schema_name.empty() ? backQuoteIfNeed(table_name) : backQuoteIfNeed(schema_name) + "." + backQuoteIfNeed(table_name);
WriteBufferFromOwnString buf;
std::string input = "SELECT * FROM " + name + " WHERE 1 = 0";
ParserQueryWithOutput parser(input.data() + input.size());
ASTPtr select = parseQuery(parser, input.data(), input.data() + input.size(), "", context_settings.max_query_size, context_settings.max_parser_depth);
IAST::FormatSettings settings(buf, true);
settings.always_quote_identifiers = true;
settings.identifier_quoting_style = getQuotingStyle(hdbc);
select->format(settings);
std::string query = buf.str();
LOG_TRACE(log, "Inferring structure with query '{}'", query);
if (POCO_SQL_ODBC_CLASS::Utility::isError(POCO_SQL_ODBC_CLASS::SQLPrepare(hstmt, reinterpret_cast<SQLCHAR *>(query.data()), query.size())))
throw POCO_SQL_ODBC_CLASS::DescriptorException(session.dbc());
if (POCO_SQL_ODBC_CLASS::Utility::isError(SQLExecute(hstmt)))
throw POCO_SQL_ODBC_CLASS::StatementException(hstmt);
SQLSMALLINT cols = 0;
if (POCO_SQL_ODBC_CLASS::Utility::isError(SQLNumResultCols(hstmt, &cols)))
throw POCO_SQL_ODBC_CLASS::StatementException(hstmt);
/// TODO cols not checked
NamesAndTypesList columns;
for (SQLSMALLINT ncol = 1; ncol <= cols; ++ncol)
{ {
SQLSMALLINT type = 0; nanodbc::catalog::tables tables = catalog.find_tables(table_name, /* type = */ "", /* schema = */ "", /* catalog = */ schema_name);
/// TODO Why 301? if (tables.next())
SQLCHAR column_name[301];
SQLSMALLINT is_nullable;
const auto result = POCO_SQL_ODBC_CLASS::SQLDescribeCol(hstmt, ncol, column_name, sizeof(column_name), nullptr, &type, nullptr, nullptr, &is_nullable);
if (POCO_SQL_ODBC_CLASS::Utility::isError(result))
throw POCO_SQL_ODBC_CLASS::StatementException(hstmt);
auto column_type = getDataType(type);
if (external_table_functions_use_nulls && is_nullable == SQL_NULLABLE)
{ {
column_type = std::make_shared<DataTypeNullable>(column_type); catalog_name = tables.table_catalog();
LOG_TRACE(log, "Will fetch info for table '{}.{}'", catalog_name, table_name);
return catalog.find_columns(/* column = */ "", table_name, /* schema = */ "", catalog_name);
} }
columns.emplace_back(reinterpret_cast<char *>(column_name), std::move(column_type)); tables = catalog.find_tables(table_name, /* type = */ "", /* schema = */ schema_name);
if (tables.next())
{
catalog_name = tables.table_catalog();
LOG_TRACE(log, "Will fetch info for table '{}.{}.{}'", catalog_name, schema_name, table_name);
return catalog.find_columns(/* column = */ "", table_name, schema_name, catalog_name);
}
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Table {} not found", schema_name.empty() ? table_name : schema_name + '.' + table_name);
};
nanodbc::catalog::columns columns_definition = get_columns();
NamesAndTypesList columns;
while (columns_definition.next())
{
SQLSMALLINT type = columns_definition.sql_data_type();
std::string column_name = columns_definition.column_name();
bool is_nullable = columns_definition.nullable() == SQL_NULLABLE;
auto column_type = getDataType(type);
if (external_table_functions_use_nulls && is_nullable == SQL_NULLABLE)
column_type = std::make_shared<DataTypeNullable>(column_type);
columns.emplace_back(column_name, std::move(column_type));
} }
if (columns.empty())
throw Exception("Columns definition was not returned", ErrorCodes::LOGICAL_ERROR);
WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout); WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout);
try try
{ {

View File

@ -2,16 +2,13 @@
#if USE_ODBC #if USE_ODBC
# include <Interpreters/Context_fwd.h> #include <Interpreters/Context_fwd.h>
# include <Server/HTTP/HTTPRequestHandler.h> #include <Interpreters/Context.h>
# include <Common/config.h> #include <Server/HTTP/HTTPRequestHandler.h>
#include <Common/config.h>
#include <Poco/Logger.h>
# include <Poco/Logger.h>
/** The structure of the table is taken from the query "SELECT * FROM table WHERE 1=0".
* TODO: It would be much better to utilize ODBC methods dedicated for columns description.
* If there is no such table, an exception is thrown.
*/
namespace DB namespace DB
{ {
@ -19,7 +16,9 @@ class ODBCColumnsInfoHandler : public HTTPRequestHandler, WithContext
{ {
public: public:
ODBCColumnsInfoHandler(size_t keep_alive_timeout_, ContextPtr context_) ODBCColumnsInfoHandler(size_t keep_alive_timeout_, ContextPtr context_)
: WithContext(context_), log(&Poco::Logger::get("ODBCColumnsInfoHandler")), keep_alive_timeout(keep_alive_timeout_) : WithContext(context_)
, log(&Poco::Logger::get("ODBCColumnsInfoHandler"))
, keep_alive_timeout(keep_alive_timeout_)
{ {
} }

View File

@ -38,9 +38,9 @@ std::unique_ptr<HTTPRequestHandler> ODBCBridgeHandlerFactory::createRequestHandl
return nullptr; return nullptr;
#endif #endif
else if (uri.getPath() == "/write") else if (uri.getPath() == "/write")
return std::make_unique<ODBCHandler>(pool_map, keep_alive_timeout, getContext(), "write"); return std::make_unique<ODBCHandler>(keep_alive_timeout, getContext(), "write");
else else
return std::make_unique<ODBCHandler>(pool_map, keep_alive_timeout, getContext(), "read"); return std::make_unique<ODBCHandler>(keep_alive_timeout, getContext(), "read");
} }
return nullptr; return nullptr;
} }

View File

@ -6,14 +6,8 @@
#include "IdentifierQuoteHandler.h" #include "IdentifierQuoteHandler.h"
#include "MainHandler.h" #include "MainHandler.h"
#include "SchemaAllowedHandler.h" #include "SchemaAllowedHandler.h"
#include <Poco/Logger.h> #include <Poco/Logger.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <Poco/Data/SessionPool.h>
#pragma GCC diagnostic pop
namespace DB namespace DB
{ {
@ -24,9 +18,11 @@ class ODBCBridgeHandlerFactory : public HTTPRequestHandlerFactory, WithContext
{ {
public: public:
ODBCBridgeHandlerFactory(const std::string & name_, size_t keep_alive_timeout_, ContextPtr context_) ODBCBridgeHandlerFactory(const std::string & name_, size_t keep_alive_timeout_, ContextPtr context_)
: WithContext(context_), log(&Poco::Logger::get(name_)), name(name_), keep_alive_timeout(keep_alive_timeout_) : WithContext(context_)
, log(&Poco::Logger::get(name_))
, name(name_)
, keep_alive_timeout(keep_alive_timeout_)
{ {
pool_map = std::make_shared<ODBCHandler::PoolMap>();
} }
std::unique_ptr<HTTPRequestHandler> createRequestHandler(const HTTPServerRequest & request) override; std::unique_ptr<HTTPRequestHandler> createRequestHandler(const HTTPServerRequest & request) override;
@ -35,7 +31,6 @@ private:
Poco::Logger * log; Poco::Logger * log;
std::string name; std::string name;
size_t keep_alive_timeout; size_t keep_alive_timeout;
std::shared_ptr<ODBCHandler::PoolMap> pool_map;
}; };
} }

View File

@ -2,23 +2,20 @@
#if USE_ODBC #if USE_ODBC
# include <DataTypes/DataTypeFactory.h> #include <DataTypes/DataTypeFactory.h>
# include <Server/HTTP/HTMLForm.h> #include <Server/HTTP/HTMLForm.h>
# include <Server/HTTP/WriteBufferFromHTTPServerResponse.h> #include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
# include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
# include <Parsers/ParserQueryWithOutput.h> #include <Parsers/ParserQueryWithOutput.h>
# include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>
# include <Poco/Data/ODBC/ODBCException.h> #include <Poco/Net/HTTPServerRequest.h>
# include <Poco/Data/ODBC/SessionImpl.h> #include <Poco/Net/HTTPServerResponse.h>
# include <Poco/Data/ODBC/Utility.h> #include <common/logger_useful.h>
# include <Poco/Net/HTTPServerRequest.h> #include <ext/scope_guard.h>
# include <Poco/Net/HTTPServerResponse.h> #include "getIdentifierQuote.h"
# include <common/logger_useful.h> #include "validateODBCConnectionString.h"
# include <ext/scope_guard.h> #include "ODBCConnectionFactory.h"
# include "getIdentifierQuote.h"
# include "validateODBCConnectionString.h"
# define POCO_SQL_ODBC_CLASS Poco::Data::ODBC
namespace DB namespace DB
{ {
@ -44,10 +41,12 @@ void IdentifierQuoteHandler::handleRequest(HTTPServerRequest & request, HTTPServ
try try
{ {
std::string connection_string = params.get("connection_string"); std::string connection_string = params.get("connection_string");
POCO_SQL_ODBC_CLASS::SessionImpl session(validateODBCConnectionString(connection_string), DBMS_DEFAULT_CONNECT_TIMEOUT_SEC);
SQLHDBC hdbc = session.dbc().handle();
auto identifier = getIdentifierQuote(hdbc); auto connection = ODBCConnectionFactory::instance().get(
validateODBCConnectionString(connection_string),
getContext()->getSettingsRef().odbc_bridge_connection_pool_size);
auto identifier = getIdentifierQuote(*connection);
WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout); WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout);
try try

View File

@ -11,11 +11,13 @@
namespace DB namespace DB
{ {
class IdentifierQuoteHandler : public HTTPRequestHandler class IdentifierQuoteHandler : public HTTPRequestHandler, WithContext
{ {
public: public:
IdentifierQuoteHandler(size_t keep_alive_timeout_, ContextPtr) IdentifierQuoteHandler(size_t keep_alive_timeout_, ContextPtr context_)
: log(&Poco::Logger::get("IdentifierQuoteHandler")), keep_alive_timeout(keep_alive_timeout_) : WithContext(context_)
, log(&Poco::Logger::get("IdentifierQuoteHandler"))
, keep_alive_timeout(keep_alive_timeout_)
{ {
} }

View File

@ -18,18 +18,17 @@
#include <Processors/Formats/InputStreamFromInputFormat.h> #include <Processors/Formats/InputStreamFromInputFormat.h>
#include <common/logger_useful.h> #include <common/logger_useful.h>
#include <Server/HTTP/HTMLForm.h> #include <Server/HTTP/HTMLForm.h>
#include "ODBCConnectionFactory.h"
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <nanodbc/nanodbc.h>
#if USE_ODBC
#include <Poco/Data/ODBC/SessionImpl.h>
#define POCO_SQL_ODBC_CLASS Poco::Data::ODBC
#endif
namespace DB namespace DB
{ {
namespace namespace
{ {
std::unique_ptr<Block> parseColumns(std::string && column_string) std::unique_ptr<Block> parseColumns(std::string && column_string)
@ -42,37 +41,6 @@ namespace
} }
} }
using PocoSessionPoolConstructor = std::function<std::shared_ptr<Poco::Data::SessionPool>()>;
/** Is used to adjust max size of default Poco thread pool. See issue #750
* Acquire the lock, resize pool and construct new Session.
*/
static std::shared_ptr<Poco::Data::SessionPool> createAndCheckResizePocoSessionPool(PocoSessionPoolConstructor pool_constr)
{
static std::mutex mutex;
Poco::ThreadPool & pool = Poco::ThreadPool::defaultPool();
/// NOTE: The lock don't guarantee that external users of the pool don't change its capacity
std::unique_lock lock(mutex);
if (pool.available() == 0)
pool.addCapacity(2 * std::max(pool.capacity(), 1));
return pool_constr();
}
ODBCHandler::PoolPtr ODBCHandler::getPool(const std::string & connection_str)
{
std::lock_guard lock(mutex);
if (!pool_map->count(connection_str))
{
pool_map->emplace(connection_str, createAndCheckResizePocoSessionPool([connection_str]
{
return std::make_shared<Poco::Data::SessionPool>("ODBC", validateODBCConnectionString(connection_str));
}));
}
return pool_map->at(connection_str);
}
void ODBCHandler::processError(HTTPServerResponse & response, const std::string & message) void ODBCHandler::processError(HTTPServerResponse & response, const std::string & message)
{ {
@ -82,6 +50,7 @@ void ODBCHandler::processError(HTTPServerResponse & response, const std::string
LOG_WARNING(log, message); LOG_WARNING(log, message);
} }
void ODBCHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) void ODBCHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
{ {
HTMLForm params(request); HTMLForm params(request);
@ -141,6 +110,10 @@ void ODBCHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse
try try
{ {
auto connection = ODBCConnectionFactory::instance().get(
validateODBCConnectionString(connection_string),
getContext()->getSettingsRef().odbc_bridge_connection_pool_size);
if (mode == "write") if (mode == "write")
{ {
if (!params.has("db_name")) if (!params.has("db_name"))
@ -159,15 +132,12 @@ void ODBCHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse
auto quoting_style = IdentifierQuotingStyle::None; auto quoting_style = IdentifierQuotingStyle::None;
#if USE_ODBC #if USE_ODBC
POCO_SQL_ODBC_CLASS::SessionImpl session(validateODBCConnectionString(connection_string), DBMS_DEFAULT_CONNECT_TIMEOUT_SEC); quoting_style = getQuotingStyle(*connection);
quoting_style = getQuotingStyle(session.dbc().handle());
#endif #endif
auto pool = getPool(connection_string);
auto & read_buf = request.getStream(); auto & read_buf = request.getStream();
auto input_format = FormatFactory::instance().getInput(format, read_buf, *sample_block, getContext(), max_block_size); auto input_format = FormatFactory::instance().getInput(format, read_buf, *sample_block, getContext(), max_block_size);
auto input_stream = std::make_shared<InputStreamFromInputFormat>(input_format); auto input_stream = std::make_shared<InputStreamFromInputFormat>(input_format);
ODBCBlockOutputStream output_stream(pool->get(), db_name, table_name, *sample_block, quoting_style); ODBCBlockOutputStream output_stream(*connection, db_name, table_name, *sample_block, getContext(), quoting_style);
copyData(*input_stream, output_stream); copyData(*input_stream, output_stream);
writeStringBinary("Ok.", out); writeStringBinary("Ok.", out);
} }
@ -176,10 +146,8 @@ void ODBCHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse
std::string query = params.get("query"); std::string query = params.get("query");
LOG_TRACE(log, "Query: {}", query); LOG_TRACE(log, "Query: {}", query);
BlockOutputStreamPtr writer BlockOutputStreamPtr writer = FormatFactory::instance().getOutputStreamParallelIfPossible(format, out, *sample_block, getContext());
= FormatFactory::instance().getOutputStreamParallelIfPossible(format, out, *sample_block, getContext()); ODBCBlockInputStream inp(*connection, query, *sample_block, max_block_size);
auto pool = getPool(connection_string);
ODBCBlockInputStream inp(pool->get(), query, *sample_block, max_block_size);
copyData(inp, *writer); copyData(inp, *writer);
} }
} }

View File

@ -2,13 +2,8 @@
#include <Interpreters/Context_fwd.h> #include <Interpreters/Context_fwd.h>
#include <Server/HTTP/HTTPRequestHandler.h> #include <Server/HTTP/HTTPRequestHandler.h>
#include <Poco/Logger.h> #include <Poco/Logger.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <Poco/Data/SessionPool.h>
#pragma GCC diagnostic pop
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
@ -24,16 +19,12 @@ namespace DB
class ODBCHandler : public HTTPRequestHandler, WithContext class ODBCHandler : public HTTPRequestHandler, WithContext
{ {
public: public:
using PoolPtr = std::shared_ptr<Poco::Data::SessionPool>; ODBCHandler(
using PoolMap = std::unordered_map<std::string, PoolPtr>;
ODBCHandler(std::shared_ptr<PoolMap> pool_map_,
size_t keep_alive_timeout_, size_t keep_alive_timeout_,
ContextPtr context_, ContextPtr context_,
const String & mode_) const String & mode_)
: WithContext(context_) : WithContext(context_)
, log(&Poco::Logger::get("ODBCHandler")) , log(&Poco::Logger::get("ODBCHandler"))
, pool_map(pool_map_)
, keep_alive_timeout(keep_alive_timeout_) , keep_alive_timeout(keep_alive_timeout_)
, mode(mode_) , mode(mode_)
{ {
@ -44,13 +35,11 @@ public:
private: private:
Poco::Logger * log; Poco::Logger * log;
std::shared_ptr<PoolMap> pool_map;
size_t keep_alive_timeout; size_t keep_alive_timeout;
String mode; String mode;
static inline std::mutex mutex; static inline std::mutex mutex;
PoolPtr getPool(const std::string & connection_str);
void processError(HTTPServerResponse & response, const std::string & message); void processError(HTTPServerResponse & response, const std::string & message);
}; };

View File

@ -1,5 +1,7 @@
#include "ODBCBlockInputStream.h" #include "ODBCBlockInputStream.h"
#include <vector> #include <vector>
#include <IO/ReadBufferFromString.h>
#include <DataTypes/DataTypeNullable.h>
#include <Columns/ColumnNullable.h> #include <Columns/ColumnNullable.h>
#include <Columns/ColumnString.h> #include <Columns/ColumnString.h>
#include <Columns/ColumnsNumber.h> #include <Columns/ColumnsNumber.h>
@ -14,137 +16,143 @@ namespace DB
{ {
namespace ErrorCodes namespace ErrorCodes
{ {
extern const int NUMBER_OF_COLUMNS_DOESNT_MATCH;
extern const int UNKNOWN_TYPE; extern const int UNKNOWN_TYPE;
} }
ODBCBlockInputStream::ODBCBlockInputStream( ODBCBlockInputStream::ODBCBlockInputStream(
Poco::Data::Session && session_, const std::string & query_str, const Block & sample_block, const UInt64 max_block_size_) nanodbc::connection & connection_, const std::string & query_str, const Block & sample_block, const UInt64 max_block_size_)
: session{session_} : log(&Poco::Logger::get("ODBCBlockInputStream"))
, statement{(this->session << query_str, Poco::Data::Keywords::now)}
, result{statement}
, iterator{result.begin()}
, max_block_size{max_block_size_} , max_block_size{max_block_size_}
, log(&Poco::Logger::get("ODBCBlockInputStream")) , connection(connection_)
, query(query_str)
{ {
if (sample_block.columns() != result.columnCount())
throw Exception{"RecordSet contains " + toString(result.columnCount()) + " columns while " + toString(sample_block.columns())
+ " expected",
ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH};
description.init(sample_block); description.init(sample_block);
} result = execute(connection, NANODBC_TEXT(query));
namespace
{
using ValueType = ExternalResultDescription::ValueType;
void insertValue(IColumn & column, const ValueType type, const Poco::Dynamic::Var & value)
{
switch (type)
{
case ValueType::vtUInt8:
assert_cast<ColumnUInt8 &>(column).insertValue(value.convert<UInt64>());
break;
case ValueType::vtUInt16:
assert_cast<ColumnUInt16 &>(column).insertValue(value.convert<UInt64>());
break;
case ValueType::vtUInt32:
assert_cast<ColumnUInt32 &>(column).insertValue(value.convert<UInt64>());
break;
case ValueType::vtUInt64:
assert_cast<ColumnUInt64 &>(column).insertValue(value.convert<UInt64>());
break;
case ValueType::vtInt8:
assert_cast<ColumnInt8 &>(column).insertValue(value.convert<Int64>());
break;
case ValueType::vtInt16:
assert_cast<ColumnInt16 &>(column).insertValue(value.convert<Int64>());
break;
case ValueType::vtInt32:
assert_cast<ColumnInt32 &>(column).insertValue(value.convert<Int64>());
break;
case ValueType::vtInt64:
assert_cast<ColumnInt64 &>(column).insertValue(value.convert<Int64>());
break;
case ValueType::vtFloat32:
assert_cast<ColumnFloat32 &>(column).insertValue(value.convert<Float64>());
break;
case ValueType::vtFloat64:
assert_cast<ColumnFloat64 &>(column).insertValue(value.convert<Float64>());
break;
case ValueType::vtString:
assert_cast<ColumnString &>(column).insert(value.convert<String>());
break;
case ValueType::vtDate:
{
Poco::DateTime date = value.convert<Poco::DateTime>();
assert_cast<ColumnUInt16 &>(column).insertValue(UInt16{LocalDate(date.year(), date.month(), date.day()).getDayNum()});
break;
}
case ValueType::vtDateTime:
{
Poco::DateTime datetime = value.convert<Poco::DateTime>();
assert_cast<ColumnUInt32 &>(column).insertValue(DateLUT::instance().makeDateTime(
datetime.year(), datetime.month(), datetime.day(), datetime.hour(), datetime.minute(), datetime.second()));
break;
}
case ValueType::vtUUID:
assert_cast<ColumnUInt128 &>(column).insert(parse<UUID>(value.convert<std::string>()));
break;
default:
throw Exception("Unsupported value type", ErrorCodes::UNKNOWN_TYPE);
}
}
void insertDefaultValue(IColumn & column, const IColumn & sample_column) { column.insertFrom(sample_column, 0); }
} }
Block ODBCBlockInputStream::readImpl() Block ODBCBlockInputStream::readImpl()
{ {
if (iterator == result.end()) if (finished)
return {}; return Block();
MutableColumns columns(description.sample_block.columns());
for (const auto i : ext::range(0, columns.size()))
columns[i] = description.sample_block.getByPosition(i).column->cloneEmpty();
MutableColumns columns(description.sample_block.cloneEmptyColumns());
size_t num_rows = 0; size_t num_rows = 0;
while (iterator != result.end())
while (true)
{ {
Poco::Data::Row & row = *iterator; if (!result.next())
for (const auto idx : ext::range(0, row.fieldCount()))
{ {
/// TODO This is extremely slow. finished = true;
const Poco::Dynamic::Var & value = row[idx]; break;
}
if (!value.isEmpty()) for (int idx = 0; idx < result.columns(); ++idx)
{
const auto & sample = description.sample_block.getByPosition(idx);
if (!result.is_null(idx))
{ {
if (description.types[idx].second) bool is_nullable = description.types[idx].second;
if (is_nullable)
{ {
ColumnNullable & column_nullable = assert_cast<ColumnNullable &>(*columns[idx]); ColumnNullable & column_nullable = assert_cast<ColumnNullable &>(*columns[idx]);
insertValue(column_nullable.getNestedColumn(), description.types[idx].first, value); const auto & data_type = assert_cast<const DataTypeNullable &>(*sample.type);
insertValue(column_nullable.getNestedColumn(), data_type.getNestedType(), description.types[idx].first, result, idx);
column_nullable.getNullMapData().emplace_back(0); column_nullable.getNullMapData().emplace_back(0);
} }
else else
insertValue(*columns[idx], description.types[idx].first, value); {
insertValue(*columns[idx], sample.type, description.types[idx].first, result, idx);
}
} }
else else
insertDefaultValue(*columns[idx], *description.sample_block.getByPosition(idx).column); insertDefaultValue(*columns[idx], *sample.column);
} }
++iterator; if (++num_rows == max_block_size)
++num_rows;
if (num_rows == max_block_size)
break; break;
} }
return description.sample_block.cloneWithColumns(std::move(columns)); return description.sample_block.cloneWithColumns(std::move(columns));
} }
void ODBCBlockInputStream::insertValue(
IColumn & column, const DataTypePtr data_type, const ValueType type, nanodbc::result & row, size_t idx)
{
switch (type)
{
case ValueType::vtUInt8:
assert_cast<ColumnUInt8 &>(column).insertValue(row.get<uint16_t>(idx));
break;
case ValueType::vtUInt16:
assert_cast<ColumnUInt16 &>(column).insertValue(row.get<uint16_t>(idx));
break;
case ValueType::vtUInt32:
assert_cast<ColumnUInt32 &>(column).insertValue(row.get<uint32_t>(idx));
break;
case ValueType::vtUInt64:
assert_cast<ColumnUInt64 &>(column).insertValue(row.get<uint64_t>(idx));
break;
case ValueType::vtInt8:
assert_cast<ColumnInt8 &>(column).insertValue(row.get<int16_t>(idx));
break;
case ValueType::vtInt16:
assert_cast<ColumnInt16 &>(column).insertValue(row.get<int16_t>(idx));
break;
case ValueType::vtInt32:
assert_cast<ColumnInt32 &>(column).insertValue(row.get<int32_t>(idx));
break;
case ValueType::vtInt64:
assert_cast<ColumnInt64 &>(column).insertValue(row.get<int64_t>(idx));
break;
case ValueType::vtFloat32:
assert_cast<ColumnFloat32 &>(column).insertValue(row.get<float>(idx));
break;
case ValueType::vtFloat64:
assert_cast<ColumnFloat64 &>(column).insertValue(row.get<double>(idx));
break;
case ValueType::vtFixedString:[[fallthrough]];
case ValueType::vtString:
assert_cast<ColumnString &>(column).insert(row.get<std::string>(idx));
break;
case ValueType::vtUUID:
{
auto value = row.get<std::string>(idx);
assert_cast<ColumnUInt128 &>(column).insert(parse<UUID>(value.data(), value.size()));
break;
}
case ValueType::vtDate:
assert_cast<ColumnUInt16 &>(column).insertValue(UInt16{LocalDate{row.get<std::string>(idx)}.getDayNum()});
break;
case ValueType::vtDateTime:
{
auto value = row.get<std::string>(idx);
ReadBufferFromString in(value);
time_t time = 0;
readDateTimeText(time, in);
if (time < 0)
time = 0;
assert_cast<ColumnUInt32 &>(column).insertValue(time);
break;
}
case ValueType::vtDateTime64:[[fallthrough]];
case ValueType::vtDecimal32: [[fallthrough]];
case ValueType::vtDecimal64: [[fallthrough]];
case ValueType::vtDecimal128: [[fallthrough]];
case ValueType::vtDecimal256:
{
auto value = row.get<std::string>(idx);
ReadBufferFromString istr(value);
data_type->getDefaultSerialization()->deserializeWholeText(column, istr, FormatSettings{});
break;
}
default:
throw Exception("Unsupported value type", ErrorCodes::UNKNOWN_TYPE);
}
}
} }

View File

@ -3,10 +3,8 @@
#include <string> #include <string>
#include <Core/Block.h> #include <Core/Block.h>
#include <DataStreams/IBlockInputStream.h> #include <DataStreams/IBlockInputStream.h>
#include <Poco/Data/RecordSet.h>
#include <Poco/Data/Session.h>
#include <Poco/Data/Statement.h>
#include <Core/ExternalResultDescription.h> #include <Core/ExternalResultDescription.h>
#include <nanodbc/nanodbc.h>
namespace DB namespace DB
@ -15,25 +13,33 @@ namespace DB
class ODBCBlockInputStream final : public IBlockInputStream class ODBCBlockInputStream final : public IBlockInputStream
{ {
public: public:
ODBCBlockInputStream( ODBCBlockInputStream(nanodbc::connection & connection_, const std::string & query_str, const Block & sample_block, const UInt64 max_block_size_);
Poco::Data::Session && session_, const std::string & query_str, const Block & sample_block, const UInt64 max_block_size_);
String getName() const override { return "ODBC"; } String getName() const override { return "ODBC"; }
Block getHeader() const override { return description.sample_block.cloneEmpty(); } Block getHeader() const override { return description.sample_block.cloneEmpty(); }
private: private:
using QueryResult = std::shared_ptr<nanodbc::result>;
using ValueType = ExternalResultDescription::ValueType;
Block readImpl() override; Block readImpl() override;
Poco::Data::Session session; static void insertValue(IColumn & column, const DataTypePtr data_type, const ValueType type, nanodbc::result & row, size_t idx);
Poco::Data::Statement statement;
Poco::Data::RecordSet result;
Poco::Data::RecordSet::Iterator iterator;
static void insertDefaultValue(IColumn & column, const IColumn & sample_column)
{
column.insertFrom(sample_column, 0);
}
Poco::Logger * log;
const UInt64 max_block_size; const UInt64 max_block_size;
ExternalResultDescription description; ExternalResultDescription description;
Poco::Logger * log; nanodbc::connection & connection;
nanodbc::result result;
String query;
bool finished = false;
}; };
} }

View File

@ -8,16 +8,14 @@
#include <Parsers/ASTExpressionList.h> #include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
#include "getIdentifierQuote.h" #include "getIdentifierQuote.h"
#include <IO/WriteHelpers.h>
#include <IO/Operators.h>
#include <Formats/FormatFactory.h>
namespace DB namespace DB
{ {
namespace ErrorCodes
{
extern const int UNKNOWN_TYPE;
}
namespace namespace
{ {
using ValueType = ExternalResultDescription::ValueType; using ValueType = ExternalResultDescription::ValueType;
@ -40,69 +38,21 @@ namespace
return buf.str(); return buf.str();
} }
std::string getQuestionMarks(size_t n)
{
std::string result = "(";
for (size_t i = 0; i < n; ++i)
{
if (i > 0)
result += ",";
result += "?";
}
return result + ")";
}
Poco::Dynamic::Var getVarFromField(const Field & field, const ValueType type)
{
switch (type)
{
case ValueType::vtUInt8:
return Poco::Dynamic::Var(static_cast<UInt64>(field.get<UInt64>())).convert<UInt64>();
case ValueType::vtUInt16:
return Poco::Dynamic::Var(static_cast<UInt64>(field.get<UInt64>())).convert<UInt64>();
case ValueType::vtUInt32:
return Poco::Dynamic::Var(static_cast<UInt64>(field.get<UInt64>())).convert<UInt64>();
case ValueType::vtUInt64:
return Poco::Dynamic::Var(field.get<UInt64>()).convert<UInt64>();
case ValueType::vtInt8:
return Poco::Dynamic::Var(static_cast<Int64>(field.get<Int64>())).convert<Int64>();
case ValueType::vtInt16:
return Poco::Dynamic::Var(static_cast<Int64>(field.get<Int64>())).convert<Int64>();
case ValueType::vtInt32:
return Poco::Dynamic::Var(static_cast<Int64>(field.get<Int64>())).convert<Int64>();
case ValueType::vtInt64:
return Poco::Dynamic::Var(field.get<Int64>()).convert<Int64>();
case ValueType::vtFloat32:
return Poco::Dynamic::Var(field.get<Float64>()).convert<Float64>();
case ValueType::vtFloat64:
return Poco::Dynamic::Var(field.get<Float64>()).convert<Float64>();
case ValueType::vtString:
return Poco::Dynamic::Var(field.get<String>()).convert<String>();
case ValueType::vtDate:
return Poco::Dynamic::Var(LocalDate(DayNum(field.get<UInt64>())).toString()).convert<String>();
case ValueType::vtDateTime:
return Poco::Dynamic::Var(DateLUT::instance().timeToString(time_t(field.get<UInt64>()))).convert<String>();
case ValueType::vtUUID:
return Poco::Dynamic::Var(UUID(field.get<UInt128>()).toUnderType().toHexString()).convert<std::string>();
default:
throw Exception("Unsupported value type", ErrorCodes::UNKNOWN_TYPE);
}
__builtin_unreachable();
}
} }
ODBCBlockOutputStream::ODBCBlockOutputStream(Poco::Data::Session && session_, ODBCBlockOutputStream::ODBCBlockOutputStream(nanodbc::connection & connection_,
const std::string & remote_database_name_, const std::string & remote_database_name_,
const std::string & remote_table_name_, const std::string & remote_table_name_,
const Block & sample_block_, const Block & sample_block_,
ContextPtr local_context_,
IdentifierQuotingStyle quoting_) IdentifierQuotingStyle quoting_)
: session(session_) : log(&Poco::Logger::get("ODBCBlockOutputStream"))
, connection(connection_)
, db_name(remote_database_name_) , db_name(remote_database_name_)
, table_name(remote_table_name_) , table_name(remote_table_name_)
, sample_block(sample_block_) , sample_block(sample_block_)
, local_context(local_context_)
, quoting(quoting_) , quoting(quoting_)
, log(&Poco::Logger::get("ODBCBlockOutputStream"))
{ {
description.init(sample_block); description.init(sample_block);
} }
@ -114,28 +64,12 @@ Block ODBCBlockOutputStream::getHeader() const
void ODBCBlockOutputStream::write(const Block & block) void ODBCBlockOutputStream::write(const Block & block)
{ {
ColumnsWithTypeAndName columns; WriteBufferFromOwnString values_buf;
for (size_t i = 0; i < block.columns(); ++i) auto writer = FormatFactory::instance().getOutputStream("Values", values_buf, sample_block, local_context);
columns.push_back({block.getColumns()[i], sample_block.getDataTypes()[i], sample_block.getNames()[i]}); writer->write(block);
std::vector<Poco::Dynamic::Var> row_to_insert(block.columns()); std::string query = getInsertQuery(db_name, table_name, block.getColumnsWithTypeAndName(), quoting) + values_buf.str();
Poco::Data::Statement statement(session << getInsertQuery(db_name, table_name, columns, quoting) + getQuestionMarks(block.columns())); execute(connection, query);
for (size_t i = 0; i < block.columns(); ++i)
statement.addBind(Poco::Data::Keywords::use(row_to_insert[i]));
for (size_t i = 0; i < block.rows(); ++i)
{
for (size_t col_idx = 0; col_idx < block.columns(); ++col_idx)
{
Field val;
columns[col_idx].column->get(i, val);
if (val.isNull())
row_to_insert[col_idx] = Poco::Dynamic::Var();
else
row_to_insert[col_idx] = getVarFromField(val, description.types[col_idx].first);
}
statement.execute();
}
} }
} }

View File

@ -2,30 +2,41 @@
#include <Core/Block.h> #include <Core/Block.h>
#include <DataStreams/IBlockOutputStream.h> #include <DataStreams/IBlockOutputStream.h>
#include <Poco/Data/Session.h>
#include <Core/ExternalResultDescription.h> #include <Core/ExternalResultDescription.h>
#include <Parsers/IdentifierQuotingStyle.h> #include <Parsers/IdentifierQuotingStyle.h>
#include <Interpreters/Context_fwd.h>
#include <nanodbc/nanodbc.h>
namespace DB namespace DB
{ {
class ODBCBlockOutputStream : public IBlockOutputStream class ODBCBlockOutputStream : public IBlockOutputStream
{ {
public: public:
ODBCBlockOutputStream(Poco::Data::Session && session_, const std::string & remote_database_name_, ODBCBlockOutputStream(
const std::string & remote_table_name_, const Block & sample_block_, IdentifierQuotingStyle quoting); nanodbc::connection & connection_,
const std::string & remote_database_name_,
const std::string & remote_table_name_,
const Block & sample_block_,
ContextPtr local_context_,
IdentifierQuotingStyle quoting);
Block getHeader() const override; Block getHeader() const override;
void write(const Block & block) override; void write(const Block & block) override;
private: private:
Poco::Data::Session session; Poco::Logger * log;
nanodbc::connection & connection;
std::string db_name; std::string db_name;
std::string table_name; std::string table_name;
Block sample_block; Block sample_block;
ContextPtr local_context;
IdentifierQuotingStyle quoting; IdentifierQuotingStyle quoting;
ExternalResultDescription description; ExternalResultDescription description;
Poco::Logger * log;
}; };
} }

View File

@ -0,0 +1,82 @@
#pragma once
#include <common/logger_useful.h>
#include <nanodbc/nanodbc.h>
#include <mutex>
#include <common/BorrowedObjectPool.h>
#include <unordered_map>
namespace nanodbc
{
static constexpr inline auto ODBC_CONNECT_TIMEOUT = 100;
using ConnectionPtr = std::shared_ptr<nanodbc::connection>;
using Pool = BorrowedObjectPool<ConnectionPtr>;
using PoolPtr = std::shared_ptr<Pool>;
class ConnectionHolder
{
public:
ConnectionHolder(const std::string & connection_string_, PoolPtr pool_) : connection_string(connection_string_), pool(pool_) {}
~ConnectionHolder()
{
if (connection)
pool->returnObject(std::move(connection));
}
nanodbc::connection & operator*()
{
if (!connection)
{
pool->borrowObject(connection, [&]()
{
return std::make_shared<nanodbc::connection>(connection_string, ODBC_CONNECT_TIMEOUT);
});
}
return *connection;
}
private:
std::string connection_string;
PoolPtr pool;
ConnectionPtr connection;
};
}
namespace DB
{
class ODBCConnectionFactory final : private boost::noncopyable
{
public:
static ODBCConnectionFactory & instance()
{
static ODBCConnectionFactory ret;
return ret;
}
nanodbc::ConnectionHolder get(const std::string & connection_string, size_t pool_size)
{
std::lock_guard lock(mutex);
if (!factory.count(connection_string))
factory.emplace(std::make_pair(connection_string, std::make_shared<nanodbc::Pool>(pool_size)));
return nanodbc::ConnectionHolder(connection_string, factory[connection_string]);
}
private:
/// [connection_settings_string] -> [connection_pool]
using PoolFactory = std::unordered_map<std::string, nanodbc::PoolPtr>;
PoolFactory factory;
std::mutex mutex;
};
}

View File

@ -2,33 +2,26 @@
#if USE_ODBC #if USE_ODBC
# include <Server/HTTP/HTMLForm.h> #include <Server/HTTP/HTMLForm.h>
# include <Server/HTTP/WriteBufferFromHTTPServerResponse.h> #include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
# include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
# include <Poco/Data/ODBC/ODBCException.h> #include <Poco/Net/HTTPServerRequest.h>
# include <Poco/Data/ODBC/SessionImpl.h> #include <Poco/Net/HTTPServerResponse.h>
# include <Poco/Data/ODBC/Utility.h> #include <common/logger_useful.h>
# include <Poco/Net/HTTPServerRequest.h> #include "validateODBCConnectionString.h"
# include <Poco/Net/HTTPServerResponse.h> #include "ODBCConnectionFactory.h"
# include <common/logger_useful.h> #include <sql.h>
# include "validateODBCConnectionString.h" #include <sqlext.h>
# define POCO_SQL_ODBC_CLASS Poco::Data::ODBC
namespace DB namespace DB
{ {
namespace namespace
{ {
bool isSchemaAllowed(SQLHDBC hdbc) bool isSchemaAllowed(nanodbc::connection & connection)
{ {
SQLUINTEGER value; uint32_t result = connection.get_info<uint32_t>(SQL_SCHEMA_USAGE);
SQLSMALLINT value_length = sizeof(value); return result != 0;
SQLRETURN r = POCO_SQL_ODBC_CLASS::SQLGetInfo(hdbc, SQL_SCHEMA_USAGE, &value, sizeof(value), &value_length);
if (POCO_SQL_ODBC_CLASS::Utility::isError(r))
throw POCO_SQL_ODBC_CLASS::ConnectionException(hdbc);
return value != 0;
} }
} }
@ -55,10 +48,12 @@ void SchemaAllowedHandler::handleRequest(HTTPServerRequest & request, HTTPServer
try try
{ {
std::string connection_string = params.get("connection_string"); std::string connection_string = params.get("connection_string");
POCO_SQL_ODBC_CLASS::SessionImpl session(validateODBCConnectionString(connection_string), DBMS_DEFAULT_CONNECT_TIMEOUT_SEC);
SQLHDBC hdbc = session.dbc().handle();
bool result = isSchemaAllowed(hdbc); auto connection = ODBCConnectionFactory::instance().get(
validateODBCConnectionString(connection_string),
getContext()->getSettingsRef().odbc_bridge_connection_pool_size);
bool result = isSchemaAllowed(*connection);
WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout); WriteBufferFromHTTPServerResponse out(response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout);
try try

View File

@ -1,22 +1,25 @@
#pragma once #pragma once
#include <Interpreters/Context.h>
#include <Server/HTTP/HTTPRequestHandler.h> #include <Server/HTTP/HTTPRequestHandler.h>
#include <Poco/Logger.h> #include <Poco/Logger.h>
#if USE_ODBC #if USE_ODBC
namespace DB namespace DB
{ {
class Context; class Context;
/// This handler establishes connection to database, and retrieves whether schema is allowed. /// This handler establishes connection to database, and retrieves whether schema is allowed.
class SchemaAllowedHandler : public HTTPRequestHandler class SchemaAllowedHandler : public HTTPRequestHandler, WithContext
{ {
public: public:
SchemaAllowedHandler(size_t keep_alive_timeout_, ContextPtr) SchemaAllowedHandler(size_t keep_alive_timeout_, ContextPtr context_)
: log(&Poco::Logger::get("SchemaAllowedHandler")), keep_alive_timeout(keep_alive_timeout_) : WithContext(context_)
, log(&Poco::Logger::get("SchemaAllowedHandler"))
, keep_alive_timeout(keep_alive_timeout_)
{ {
} }

View File

@ -2,11 +2,10 @@
#if USE_ODBC #if USE_ODBC
# include <Poco/Data/ODBC/ODBCException.h> #include <common/logger_useful.h>
# include <Poco/Data/ODBC/SessionImpl.h> #include <nanodbc/nanodbc.h>
# include <Poco/Data/ODBC/Utility.h> #include <sql.h>
#include <sqlext.h>
# define POCO_SQL_ODBC_CLASS Poco::Data::ODBC
namespace DB namespace DB
@ -17,33 +16,16 @@ namespace ErrorCodes
extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ILLEGAL_TYPE_OF_ARGUMENT;
} }
std::string getIdentifierQuote(SQLHDBC hdbc)
std::string getIdentifierQuote(nanodbc::connection & connection)
{ {
std::string identifier; return connection.get_info<std::string>(SQL_IDENTIFIER_QUOTE_CHAR);
SQLSMALLINT t;
SQLRETURN r = POCO_SQL_ODBC_CLASS::SQLGetInfo(hdbc, SQL_IDENTIFIER_QUOTE_CHAR, nullptr, 0, &t);
if (POCO_SQL_ODBC_CLASS::Utility::isError(r))
throw POCO_SQL_ODBC_CLASS::ConnectionException(hdbc);
if (t > 0)
{
// I have no idea, why to add '2' here, got from: contrib/poco/Data/ODBC/src/ODBCStatementImpl.cpp:60 (SQL_DRIVER_NAME)
identifier.resize(static_cast<std::size_t>(t) + 2);
if (POCO_SQL_ODBC_CLASS::Utility::isError(POCO_SQL_ODBC_CLASS::SQLGetInfo(
hdbc, SQL_IDENTIFIER_QUOTE_CHAR, &identifier[0], SQLSMALLINT((identifier.length() - 1) * sizeof(identifier[0])), &t)))
throw POCO_SQL_ODBC_CLASS::ConnectionException(hdbc);
identifier.resize(static_cast<std::size_t>(t));
}
return identifier;
} }
IdentifierQuotingStyle getQuotingStyle(SQLHDBC hdbc)
IdentifierQuotingStyle getQuotingStyle(nanodbc::connection & connection)
{ {
auto identifier_quote = getIdentifierQuote(hdbc); auto identifier_quote = getIdentifierQuote(connection);
if (identifier_quote.length() == 0) if (identifier_quote.length() == 0)
return IdentifierQuotingStyle::None; return IdentifierQuotingStyle::None;
else if (identifier_quote[0] == '`') else if (identifier_quote[0] == '`')

View File

@ -2,20 +2,19 @@
#if USE_ODBC #if USE_ODBC
# include <Interpreters/Context.h> #include <Interpreters/Context.h>
# include <Poco/Logger.h> #include <Poco/Logger.h>
# include <Poco/Net/HTTPRequestHandler.h> #include <Poco/Net/HTTPRequestHandler.h>
# include <Poco/Data/ODBC/Utility.h>
#include <Parsers/IdentifierQuotingStyle.h> #include <Parsers/IdentifierQuotingStyle.h>
#include <nanodbc/nanodbc.h>
namespace DB namespace DB
{ {
std::string getIdentifierQuote(SQLHDBC hdbc); std::string getIdentifierQuote(nanodbc::connection & connection);
IdentifierQuotingStyle getQuotingStyle(SQLHDBC hdbc); IdentifierQuotingStyle getQuotingStyle(nanodbc::connection & connection);
} }

View File

@ -173,18 +173,24 @@ int waitServersToFinish(std::vector<DB::ProtocolServerAdapter> & servers, size_t
const int sleep_one_ms = 100; const int sleep_one_ms = 100;
int sleep_current_ms = 0; int sleep_current_ms = 0;
int current_connections = 0; int current_connections = 0;
while (sleep_current_ms < sleep_max_ms) for (;;)
{ {
current_connections = 0; current_connections = 0;
for (auto & server : servers) for (auto & server : servers)
{ {
server.stop(); server.stop();
current_connections += server.currentConnections(); current_connections += server.currentConnections();
} }
if (!current_connections) if (!current_connections)
break; break;
sleep_current_ms += sleep_one_ms; sleep_current_ms += sleep_one_ms;
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_one_ms)); if (sleep_current_ms < sleep_max_ms)
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_one_ms));
else
break;
} }
return current_connections; return current_connections;
} }
@ -750,6 +756,7 @@ int Server::main(const std::vector<std::string> & /*args*/)
global_context->setClustersConfig(config); global_context->setClustersConfig(config);
global_context->setMacros(std::make_unique<Macros>(*config, "macros", log)); global_context->setMacros(std::make_unique<Macros>(*config, "macros", log));
global_context->setExternalAuthenticatorsConfig(*config); global_context->setExternalAuthenticatorsConfig(*config);
global_context->setExternalModelsConfig(config);
/// Setup protection to avoid accidental DROP for big tables (that are greater than 50 GB by default) /// Setup protection to avoid accidental DROP for big tables (that are greater than 50 GB by default)
if (config->has("max_table_size_to_drop")) if (config->has("max_table_size_to_drop"))
@ -878,10 +885,30 @@ int Server::main(const std::vector<std::string> & /*args*/)
servers_to_start_before_tables->emplace_back( servers_to_start_before_tables->emplace_back(
port_name, port_name,
std::make_unique<Poco::Net::TCPServer>( std::make_unique<Poco::Net::TCPServer>(
new KeeperTCPHandlerFactory(*this), server_pool, socket, new Poco::Net::TCPServerParams)); new KeeperTCPHandlerFactory(*this, false), server_pool, socket, new Poco::Net::TCPServerParams));
LOG_INFO(log, "Listening for connections to Keeper (tcp): {}", address.toString()); LOG_INFO(log, "Listening for connections to Keeper (tcp): {}", address.toString());
}); });
const char * secure_port_name = "keeper_server.tcp_port_secure";
createServer(listen_host, secure_port_name, listen_try, [&](UInt16 port)
{
#if USE_SSL
Poco::Net::SecureServerSocket socket;
auto address = socketBindListen(socket, listen_host, port, /* secure = */ true);
socket.setReceiveTimeout(settings.receive_timeout);
socket.setSendTimeout(settings.send_timeout);
servers_to_start_before_tables->emplace_back(
secure_port_name,
std::make_unique<Poco::Net::TCPServer>(
new KeeperTCPHandlerFactory(*this, true), server_pool, socket, new Poco::Net::TCPServerParams));
LOG_INFO(log, "Listening for connections to Keeper with secure protocol (tcp_secure): {}", address.toString());
#else
UNUSED(port);
throw Exception{"SSL support for TCP protocol is disabled because Poco library was built without NetSSL support.",
ErrorCodes::SUPPORT_IS_DISABLED};
#endif
});
} }
#else #else
throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, "ClickHouse server built without NuRaft library. Cannot use internal coordination."); throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, "ClickHouse server built without NuRaft library. Cannot use internal coordination.");
@ -930,6 +957,9 @@ int Server::main(const std::vector<std::string> & /*args*/)
global_context->shutdownKeeperStorageDispatcher(); global_context->shutdownKeeperStorageDispatcher();
} }
/// Wait server pool to avoid use-after-free of destroyed context in the handlers
server_pool.joinAll();
/** Explicitly destroy Context. It is more convenient than in destructor of Server, because logger is still available. /** Explicitly destroy Context. It is more convenient than in destructor of Server, because logger is still available.
* At this moment, no one could own shared part of Context. * At this moment, no one could own shared part of Context.
*/ */
@ -1302,7 +1332,7 @@ int Server::main(const std::vector<std::string> & /*args*/)
} }
/// try to load dictionaries immediately, throw on error and die /// try to load dictionaries immediately, throw on error and die
ext::scope_guard dictionaries_xmls, models_xmls; ext::scope_guard dictionaries_xmls;
try try
{ {
if (!config().getBool("dictionaries_lazy_load", true)) if (!config().getBool("dictionaries_lazy_load", true))
@ -1312,8 +1342,6 @@ int Server::main(const std::vector<std::string> & /*args*/)
} }
dictionaries_xmls = global_context->getExternalDictionariesLoader().addConfigRepository( dictionaries_xmls = global_context->getExternalDictionariesLoader().addConfigRepository(
std::make_unique<ExternalLoaderXMLConfigRepository>(config(), "dictionaries_config")); std::make_unique<ExternalLoaderXMLConfigRepository>(config(), "dictionaries_config"));
models_xmls = global_context->getExternalModelsLoader().addConfigRepository(
std::make_unique<ExternalLoaderXMLConfigRepository>(config(), "models_config"));
} }
catch (...) catch (...)
{ {

View File

@ -7,7 +7,20 @@
--> -->
<yandex> <yandex>
<logger> <logger>
<!-- Possible levels: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105 --> <!-- Possible levels [1]:
- none (turns off logging)
- fatal
- critical
- error
- warning
- notice
- information
- debug
- trace
[1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
-->
<level>trace</level> <level>trace</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log> <log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog> <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
@ -76,7 +89,7 @@
<!-- Compatibility with PostgreSQL protocol. <!-- Compatibility with PostgreSQL protocol.
ClickHouse will pretend to be PostgreSQL for applications connecting to this port. ClickHouse will pretend to be PostgreSQL for applications connecting to this port.
--> -->
<!-- <postgresql_port>9005</postgresql_port> --> <postgresql_port>9005</postgresql_port>
<!-- HTTP API with TLS (HTTPS). <!-- HTTP API with TLS (HTTPS).
You have to configure certificate to enable this interface. You have to configure certificate to enable this interface.

View File

@ -62,7 +62,7 @@ enum class AccessType
enabled implicitly by the grant ALTER_TABLE */\ enabled implicitly by the grant ALTER_TABLE */\
M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\ M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\
M(ALTER_MOVE_PARTITION, "ALTER MOVE PART, MOVE PARTITION, MOVE PART", TABLE, ALTER_TABLE) \ M(ALTER_MOVE_PARTITION, "ALTER MOVE PART, MOVE PARTITION, MOVE PART", TABLE, ALTER_TABLE) \
M(ALTER_FETCH_PARTITION, "FETCH PARTITION", TABLE, ALTER_TABLE) \ M(ALTER_FETCH_PARTITION, "ALTER FETCH PART, FETCH PARTITION", TABLE, ALTER_TABLE) \
M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION, UNFREEZE", TABLE, ALTER_TABLE) \ M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION, UNFREEZE", TABLE, ALTER_TABLE) \
\ \
M(ALTER_TABLE, "", GROUP, ALTER) \ M(ALTER_TABLE, "", GROUP, ALTER) \

View File

@ -13,17 +13,25 @@ namespace ErrorCodes
void AggregateFunctionCombinatorFactory::registerCombinator(const AggregateFunctionCombinatorPtr & value) void AggregateFunctionCombinatorFactory::registerCombinator(const AggregateFunctionCombinatorPtr & value)
{ {
if (!dict.emplace(value->getName(), value).second) CombinatorPair pair{
throw Exception("AggregateFunctionCombinatorFactory: the name '" + value->getName() + "' is not unique", .name = value->getName(),
ErrorCodes::LOGICAL_ERROR); .combinator_ptr = value,
};
/// lower_bound() cannot be used since sort order of the dict is by length of the combinator
/// but there are just a few combiners, so not a problem.
if (std::find(dict.begin(), dict.end(), pair) != dict.end())
throw Exception(ErrorCodes::LOGICAL_ERROR, "AggregateFunctionCombinatorFactory: the name '{}' is not unique",
value->getName());
dict.emplace(std::lower_bound(dict.begin(), dict.end(), pair), pair);
} }
AggregateFunctionCombinatorPtr AggregateFunctionCombinatorFactory::tryFindSuffix(const std::string & name) const AggregateFunctionCombinatorPtr AggregateFunctionCombinatorFactory::tryFindSuffix(const std::string & name) const
{ {
/// O(N) is ok for just a few combinators. /// O(N) is ok for just a few combinators.
for (const auto & suffix_value : dict) for (const auto & suffix_value : dict)
if (endsWith(name, suffix_value.first)) if (endsWith(name, suffix_value.name))
return suffix_value.second; return suffix_value.combinator_ptr;
return {}; return {};
} }

View File

@ -15,7 +15,17 @@ namespace DB
class AggregateFunctionCombinatorFactory final: private boost::noncopyable class AggregateFunctionCombinatorFactory final: private boost::noncopyable
{ {
private: private:
using Dict = std::unordered_map<std::string, AggregateFunctionCombinatorPtr>; struct CombinatorPair
{
std::string name;
AggregateFunctionCombinatorPtr combinator_ptr;
bool operator==(const CombinatorPair & rhs) const { return name == rhs.name; }
/// Sort by the length of the combinator name for proper tryFindSuffix()
/// for combiners with common prefix (i.e. "State" and "SimpleState").
bool operator<(const CombinatorPair & rhs) const { return name.length() > rhs.name.length(); }
};
using Dict = std::vector<CombinatorPair>;
Dict dict; Dict dict;
public: public:

View File

@ -551,6 +551,15 @@ void Connection::sendIgnoredPartUUIDs(const std::vector<UUID> & uuids)
out->next(); out->next();
} }
void Connection::sendReadTaskResponse(const String & response)
{
writeVarUInt(Protocol::Client::ReadTaskResponse, *out);
writeVarUInt(DBMS_CLUSTER_PROCESSING_PROTOCOL_VERSION, *out);
writeStringBinary(response, *out);
out->next();
}
void Connection::sendPreparedData(ReadBuffer & input, size_t size, const String & name) void Connection::sendPreparedData(ReadBuffer & input, size_t size, const String & name)
{ {
/// NOTE 'Throttler' is not used in this method (could use, but it's not important right now). /// NOTE 'Throttler' is not used in this method (could use, but it's not important right now).
@ -807,6 +816,9 @@ Packet Connection::receivePacket()
readVectorBinary(res.part_uuids, *in); readVectorBinary(res.part_uuids, *in);
return res; return res;
case Protocol::Server::ReadTaskRequest:
return res;
default: default:
/// In unknown state, disconnect - to not leave unsynchronised connection. /// In unknown state, disconnect - to not leave unsynchronised connection.
disconnect(); disconnect();
@ -907,13 +919,13 @@ void Connection::setDescription()
} }
std::unique_ptr<Exception> Connection::receiveException() std::unique_ptr<Exception> Connection::receiveException() const
{ {
return std::make_unique<Exception>(readException(*in, "Received from " + getDescription(), true /* remote */)); return std::make_unique<Exception>(readException(*in, "Received from " + getDescription(), true /* remote */));
} }
std::vector<String> Connection::receiveMultistringMessage(UInt64 msg_type) std::vector<String> Connection::receiveMultistringMessage(UInt64 msg_type) const
{ {
size_t num = Protocol::Server::stringsInMessage(msg_type); size_t num = Protocol::Server::stringsInMessage(msg_type);
std::vector<String> strings(num); std::vector<String> strings(num);
@ -923,7 +935,7 @@ std::vector<String> Connection::receiveMultistringMessage(UInt64 msg_type)
} }
Progress Connection::receiveProgress() Progress Connection::receiveProgress() const
{ {
Progress progress; Progress progress;
progress.read(*in, server_revision); progress.read(*in, server_revision);
@ -931,7 +943,7 @@ Progress Connection::receiveProgress()
} }
BlockStreamProfileInfo Connection::receiveProfileInfo() BlockStreamProfileInfo Connection::receiveProfileInfo() const
{ {
BlockStreamProfileInfo profile_info; BlockStreamProfileInfo profile_info;
profile_info.read(*in); profile_info.read(*in);

View File

@ -159,6 +159,8 @@ public:
/// Send parts' uuids to excluded them from query processing /// Send parts' uuids to excluded them from query processing
void sendIgnoredPartUUIDs(const std::vector<UUID> & uuids); void sendIgnoredPartUUIDs(const std::vector<UUID> & uuids);
void sendReadTaskResponse(const String &);
/// Send prepared block of data (serialized and, if need, compressed), that will be read from 'input'. /// Send prepared block of data (serialized and, if need, compressed), that will be read from 'input'.
/// You could pass size of serialized/compressed block. /// You could pass size of serialized/compressed block.
void sendPreparedData(ReadBuffer & input, size_t size, const String & name = ""); void sendPreparedData(ReadBuffer & input, size_t size, const String & name = "");
@ -269,7 +271,7 @@ private:
class LoggerWrapper class LoggerWrapper
{ {
public: public:
LoggerWrapper(Connection & parent_) explicit LoggerWrapper(Connection & parent_)
: log(nullptr), parent(parent_) : log(nullptr), parent(parent_)
{ {
} }
@ -304,10 +306,10 @@ private:
Block receiveLogData(); Block receiveLogData();
Block receiveDataImpl(BlockInputStreamPtr & stream); Block receiveDataImpl(BlockInputStreamPtr & stream);
std::vector<String> receiveMultistringMessage(UInt64 msg_type); std::vector<String> receiveMultistringMessage(UInt64 msg_type) const;
std::unique_ptr<Exception> receiveException(); std::unique_ptr<Exception> receiveException() const;
Progress receiveProgress(); Progress receiveProgress() const;
BlockStreamProfileInfo receiveProfileInfo(); BlockStreamProfileInfo receiveProfileInfo() const;
void initInputBuffers(); void initInputBuffers();
void initBlockInput(); void initBlockInput();

View File

@ -26,7 +26,7 @@ public:
using Entry = PoolBase<Connection>::Entry; using Entry = PoolBase<Connection>::Entry;
public: public:
virtual ~IConnectionPool() {} virtual ~IConnectionPool() = default;
/// Selects the connection to work. /// Selects the connection to work.
/// If force_connected is false, the client must manually ensure that returned connection is good. /// If force_connected is false, the client must manually ensure that returned connection is good.

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